From f8114bbada5f19adc46bb66d0a1962cc6463d7f4 Mon Sep 17 00:00:00 2001 From: eaglercraft Date: Sun, 19 Jan 2025 16:16:38 -0800 Subject: [PATCH] u47 --- .../resources/EPKVersionIdentifier.txt | 2 +- .../resources/assets/eagler/CREDITS.txt | 61 + .../glsl/deferred/accel_particle_forward.fsh | 5 +- .../eagler/glsl/deferred/deferred_combine.fsh | 2 +- .../eagler/glsl/deferred/deferred_fog.fsh | 2 +- .../eagler/glsl/deferred/forward_core.fsh | 7 +- .../deferred/forward_glass_highlights.fsh | 5 +- .../eagler/glsl/deferred/hand_depth_mask.fsh | 2 +- .../glsl/deferred/light_shafts_sample.fsh | 2 +- .../eagler/glsl/deferred/lighting_point.fsh | 7 +- .../eagler/glsl/deferred/lighting_sun.fsh | 16 +- .../glsl/deferred/post_bloom_bright.fsh | 2 +- .../eagler/glsl/deferred/post_tonemap.fsh | 2 +- .../glsl/deferred/realistic_water_mask.fsh | 12 +- .../glsl/deferred/realistic_water_noise.fsh | 4 +- .../glsl/deferred/realistic_water_normals.fsh | 4 +- .../deferred/realistic_water_normals_mix.fsh | 35 + .../glsl/deferred/realistic_water_render.fsh | 34 +- .../eagler/glsl/deferred/reproject_ssr.fsh | 136 +- .../glsl/deferred/shader_pack_info.json | 2 +- .../eagler/glsl/deferred/shadows_sun.fsh | 2 +- .../eagler/glsl/deferred/ssao_generate.fsh | 2 +- .../resources/assets/eagler/icudt/nfc.nrm | Bin 0 -> 35136 bytes .../resources/assets/eagler/icudt/nfkc.nrm | Bin 0 -> 54144 bytes .../resources/assets/eagler/icudt/ubidi.icu | Bin 0 -> 26640 bytes .../resources/assets/eagler/icudt/uprops.icu | Bin 0 -> 135664 bytes desktopRuntime/resources/plugin_download.zip | Bin 543940 -> 541353 bytes desktopRuntime/resources/plugin_version.json | 2 +- desktopRuntime/resources/relay_download.zip | Bin 235006 -> 235499 bytes src/game/java/net/minecraft/block/Block.java | 2 +- .../java/net/minecraft/block/BlockAir.java | 2 +- .../java/net/minecraft/block/BlockAnvil.java | 2 +- .../java/net/minecraft/block/BlockBanner.java | 2 +- .../net/minecraft/block/BlockBarrier.java | 2 +- .../block/BlockBasePressurePlate.java | 2 +- .../java/net/minecraft/block/BlockBeacon.java | 2 +- .../java/net/minecraft/block/BlockBed.java | 2 +- .../net/minecraft/block/BlockBookshelf.java | 2 +- .../net/minecraft/block/BlockBreakable.java | 2 +- .../minecraft/block/BlockBrewingStand.java | 2 +- .../java/net/minecraft/block/BlockBush.java | 2 +- .../java/net/minecraft/block/BlockButton.java | 2 +- .../net/minecraft/block/BlockButtonStone.java | 2 +- .../net/minecraft/block/BlockButtonWood.java | 2 +- .../java/net/minecraft/block/BlockCactus.java | 2 +- .../java/net/minecraft/block/BlockCake.java | 2 +- .../java/net/minecraft/block/BlockCarpet.java | 2 +- .../java/net/minecraft/block/BlockCarrot.java | 2 +- .../net/minecraft/block/BlockCauldron.java | 2 +- .../java/net/minecraft/block/BlockChest.java | 2 +- .../java/net/minecraft/block/BlockClay.java | 2 +- .../java/net/minecraft/block/BlockCocoa.java | 2 +- .../net/minecraft/block/BlockColored.java | 2 +- .../minecraft/block/BlockCommandBlock.java | 2 +- .../block/BlockCompressedPowered.java | 2 +- .../net/minecraft/block/BlockContainer.java | 2 +- .../java/net/minecraft/block/BlockCrops.java | 2 +- .../block/BlockDaylightDetector.java | 2 +- .../net/minecraft/block/BlockDeadBush.java | 2 +- .../net/minecraft/block/BlockDirectional.java | 2 +- .../java/net/minecraft/block/BlockDirt.java | 2 +- .../net/minecraft/block/BlockDispenser.java | 2 +- .../java/net/minecraft/block/BlockDoor.java | 2 +- .../net/minecraft/block/BlockDoublePlant.java | 2 +- .../minecraft/block/BlockDoubleStoneSlab.java | 2 +- .../block/BlockDoubleStoneSlabNew.java | 2 +- .../minecraft/block/BlockDoubleWoodSlab.java | 2 +- .../net/minecraft/block/BlockDragonEgg.java | 2 +- .../net/minecraft/block/BlockDropper.java | 2 +- .../minecraft/block/BlockDynamicLiquid.java | 2 +- .../block/BlockEnchantmentTable.java | 2 +- .../net/minecraft/block/BlockEndPortal.java | 2 +- .../minecraft/block/BlockEndPortalFrame.java | 2 +- .../net/minecraft/block/BlockEnderChest.java | 2 +- .../net/minecraft/block/BlockEventData.java | 2 +- .../net/minecraft/block/BlockFalling.java | 2 +- .../net/minecraft/block/BlockFarmland.java | 2 +- .../java/net/minecraft/block/BlockFence.java | 2 +- .../net/minecraft/block/BlockFenceGate.java | 2 +- .../java/net/minecraft/block/BlockFire.java | 35 +- .../java/net/minecraft/block/BlockFlower.java | 2 +- .../net/minecraft/block/BlockFlowerPot.java | 2 +- .../net/minecraft/block/BlockFurnace.java | 2 +- .../java/net/minecraft/block/BlockGlass.java | 2 +- .../net/minecraft/block/BlockGlowstone.java | 2 +- .../java/net/minecraft/block/BlockGrass.java | 2 +- .../java/net/minecraft/block/BlockGravel.java | 2 +- .../minecraft/block/BlockHalfStoneSlab.java | 2 +- .../block/BlockHalfStoneSlabNew.java | 2 +- .../minecraft/block/BlockHalfWoodSlab.java | 2 +- .../minecraft/block/BlockHardenedClay.java | 2 +- .../java/net/minecraft/block/BlockHay.java | 2 +- .../java/net/minecraft/block/BlockHopper.java | 2 +- .../minecraft/block/BlockHugeMushroom.java | 2 +- .../java/net/minecraft/block/BlockIce.java | 2 +- .../net/minecraft/block/BlockJukebox.java | 2 +- .../java/net/minecraft/block/BlockLadder.java | 2 +- .../java/net/minecraft/block/BlockLeaves.java | 2 +- .../net/minecraft/block/BlockLeavesBase.java | 2 +- .../java/net/minecraft/block/BlockLever.java | 2 +- .../net/minecraft/block/BlockLilyPad.java | 2 +- .../java/net/minecraft/block/BlockLiquid.java | 2 +- .../java/net/minecraft/block/BlockLog.java | 2 +- .../java/net/minecraft/block/BlockMelon.java | 2 +- .../net/minecraft/block/BlockMobSpawner.java | 2 +- .../net/minecraft/block/BlockMushroom.java | 2 +- .../net/minecraft/block/BlockMycelium.java | 2 +- .../net/minecraft/block/BlockNetherBrick.java | 2 +- .../net/minecraft/block/BlockNetherWart.java | 2 +- .../net/minecraft/block/BlockNetherrack.java | 2 +- .../net/minecraft/block/BlockNewLeaf.java | 2 +- .../java/net/minecraft/block/BlockNewLog.java | 2 +- .../java/net/minecraft/block/BlockNote.java | 2 +- .../net/minecraft/block/BlockObsidian.java | 2 +- .../net/minecraft/block/BlockOldLeaf.java | 2 +- .../java/net/minecraft/block/BlockOldLog.java | 2 +- .../java/net/minecraft/block/BlockOre.java | 2 +- .../net/minecraft/block/BlockPackedIce.java | 2 +- .../java/net/minecraft/block/BlockPane.java | 2 +- .../net/minecraft/block/BlockPistonBase.java | 2 +- .../minecraft/block/BlockPistonExtension.java | 2 +- .../minecraft/block/BlockPistonMoving.java | 2 +- .../java/net/minecraft/block/BlockPlanks.java | 2 +- .../java/net/minecraft/block/BlockPortal.java | 2 +- .../java/net/minecraft/block/BlockPotato.java | 2 +- .../minecraft/block/BlockPressurePlate.java | 2 +- .../block/BlockPressurePlateWeighted.java | 2 +- .../net/minecraft/block/BlockPrismarine.java | 2 +- .../net/minecraft/block/BlockPumpkin.java | 2 +- .../java/net/minecraft/block/BlockQuartz.java | 2 +- .../java/net/minecraft/block/BlockRail.java | 2 +- .../net/minecraft/block/BlockRailBase.java | 2 +- .../minecraft/block/BlockRailDetector.java | 2 +- .../net/minecraft/block/BlockRailPowered.java | 2 +- .../net/minecraft/block/BlockRedFlower.java | 2 +- .../minecraft/block/BlockRedSandstone.java | 2 +- .../block/BlockRedstoneComparator.java | 2 +- .../minecraft/block/BlockRedstoneDiode.java | 2 +- .../minecraft/block/BlockRedstoneLight.java | 2 +- .../net/minecraft/block/BlockRedstoneOre.java | 2 +- .../block/BlockRedstoneRepeater.java | 2 +- .../minecraft/block/BlockRedstoneTorch.java | 15 +- .../minecraft/block/BlockRedstoneWire.java | 2 +- .../java/net/minecraft/block/BlockReed.java | 2 +- .../minecraft/block/BlockRotatedPillar.java | 2 +- .../java/net/minecraft/block/BlockSand.java | 2 +- .../net/minecraft/block/BlockSandStone.java | 2 +- .../net/minecraft/block/BlockSapling.java | 2 +- .../net/minecraft/block/BlockSeaLantern.java | 2 +- .../java/net/minecraft/block/BlockSign.java | 2 +- .../net/minecraft/block/BlockSilverfish.java | 2 +- .../java/net/minecraft/block/BlockSkull.java | 2 +- .../java/net/minecraft/block/BlockSlab.java | 2 +- .../java/net/minecraft/block/BlockSlime.java | 2 +- .../java/net/minecraft/block/BlockSnow.java | 2 +- .../net/minecraft/block/BlockSnowBlock.java | 2 +- .../net/minecraft/block/BlockSoulSand.java | 2 +- .../net/minecraft/block/BlockSourceImpl.java | 2 +- .../java/net/minecraft/block/BlockSponge.java | 2 +- .../minecraft/block/BlockStainedGlass.java | 2 +- .../block/BlockStainedGlassPane.java | 2 +- .../java/net/minecraft/block/BlockStairs.java | 2 +- .../minecraft/block/BlockStandingSign.java | 2 +- .../minecraft/block/BlockStaticLiquid.java | 2 +- .../java/net/minecraft/block/BlockStem.java | 2 +- .../java/net/minecraft/block/BlockStone.java | 2 +- .../net/minecraft/block/BlockStoneBrick.java | 2 +- .../net/minecraft/block/BlockStoneSlab.java | 2 +- .../minecraft/block/BlockStoneSlabNew.java | 2 +- .../java/net/minecraft/block/BlockTNT.java | 2 +- .../net/minecraft/block/BlockTallGrass.java | 2 +- .../java/net/minecraft/block/BlockTorch.java | 2 +- .../net/minecraft/block/BlockTrapDoor.java | 2 +- .../net/minecraft/block/BlockTripWire.java | 2 +- .../minecraft/block/BlockTripWireHook.java | 2 +- .../java/net/minecraft/block/BlockVine.java | 2 +- .../java/net/minecraft/block/BlockWall.java | 2 +- .../net/minecraft/block/BlockWallSign.java | 2 +- .../java/net/minecraft/block/BlockWeb.java | 2 +- .../net/minecraft/block/BlockWoodSlab.java | 2 +- .../net/minecraft/block/BlockWorkbench.java | 2 +- .../minecraft/block/BlockYellowFlower.java | 2 +- .../java/net/minecraft/block/IGrowable.java | 2 +- .../minecraft/block/ITileEntityProvider.java | 2 +- .../minecraft/block/material/MapColor.java | 2 +- .../minecraft/block/material/Material.java | 2 +- .../block/material/MaterialLiquid.java | 2 +- .../block/material/MaterialLogic.java | 2 +- .../block/material/MaterialPortal.java | 2 +- .../block/material/MaterialTransparent.java | 2 +- .../minecraft/block/properties/IProperty.java | 2 +- .../block/properties/PropertyBool.java | 2 +- .../block/properties/PropertyDirection.java | 2 +- .../block/properties/PropertyEnum.java | 2 +- .../block/properties/PropertyHelper.java | 2 +- .../block/properties/PropertyInteger.java | 2 +- .../state/BlockPistonStructureHelper.java | 2 +- .../net/minecraft/block/state/BlockState.java | 2 +- .../minecraft/block/state/BlockStateBase.java | 2 +- .../block/state/BlockWorldState.java | 2 +- .../minecraft/block/state/IBlockState.java | 2 +- .../block/state/pattern/BlockHelper.java | 2 +- .../block/state/pattern/BlockPattern.java | 2 +- .../block/state/pattern/BlockStateHelper.java | 2 +- .../state/pattern/FactoryBlockPattern.java | 27 +- .../client/ClientBrandRetriever.java | 2 +- .../client/LoadingScreenRenderer.java | 2 +- .../java/net/minecraft/client/Minecraft.java | 2 +- .../minecraft/client/audio/GuardianSound.java | 2 +- .../net/minecraft/client/audio/ISound.java | 2 +- .../client/audio/ISoundEventAccessor.java | 2 +- .../client/audio/ITickableSound.java | 2 +- .../minecraft/client/audio/MovingSound.java | 2 +- .../client/audio/MovingSoundMinecart.java | 2 +- .../audio/MovingSoundMinecartRiding.java | 2 +- .../minecraft/client/audio/MusicTicker.java | 2 +- .../client/audio/PositionedSound.java | 2 +- .../client/audio/PositionedSoundRecord.java | 2 +- .../minecraft/client/audio/SoundCategory.java | 10 +- .../client/audio/SoundEventAccessor.java | 2 +- .../audio/SoundEventAccessorComposite.java | 2 +- .../minecraft/client/audio/SoundHandler.java | 2 +- .../net/minecraft/client/audio/SoundList.java | 2 +- .../client/audio/SoundListSerializer.java | 2 +- .../client/audio/SoundPoolEntry.java | 2 +- .../minecraft/client/audio/SoundRegistry.java | 2 +- .../client/entity/AbstractClientPlayer.java | 2 +- .../client/entity/EntityOtherPlayerMP.java | 2 +- .../client/entity/EntityPlayerSP.java | 2 +- .../net/minecraft/client/gui/ChatLine.java | 2 +- .../minecraft/client/gui/FontRenderer.java | 23 +- .../java/net/minecraft/client/gui/Gui.java | 2 +- .../net/minecraft/client/gui/GuiButton.java | 2 +- .../client/gui/GuiButtonLanguage.java | 2 +- .../net/minecraft/client/gui/GuiChat.java | 2 +- .../minecraft/client/gui/GuiCommandBlock.java | 2 +- .../client/gui/GuiConfirmOpenLink.java | 2 +- .../net/minecraft/client/gui/GuiControls.java | 2 +- .../client/gui/GuiCreateFlatWorld.java | 2 +- .../minecraft/client/gui/GuiCreateWorld.java | 2 +- .../client/gui/GuiCustomizeSkin.java | 2 +- .../client/gui/GuiCustomizeWorldScreen.java | 2 +- .../minecraft/client/gui/GuiDisconnected.java | 2 +- .../client/gui/GuiDownloadTerrain.java | 2 +- .../minecraft/client/gui/GuiEnchantment.java | 2 +- .../minecraft/client/gui/GuiErrorScreen.java | 2 +- .../minecraft/client/gui/GuiFlatPresets.java | 2 +- .../net/minecraft/client/gui/GuiGameOver.java | 2 +- .../net/minecraft/client/gui/GuiHopper.java | 2 +- .../net/minecraft/client/gui/GuiIngame.java | 2 +- .../minecraft/client/gui/GuiIngameMenu.java | 2 +- .../client/gui/GuiKeyBindingList.java | 2 +- .../net/minecraft/client/gui/GuiLabel.java | 2 +- .../net/minecraft/client/gui/GuiLanguage.java | 2 +- .../minecraft/client/gui/GuiListButton.java | 2 +- .../minecraft/client/gui/GuiListExtended.java | 2 +- .../client/gui/GuiLockIconButton.java | 2 +- .../net/minecraft/client/gui/GuiMainMenu.java | 2 +- .../client/gui/GuiMemoryErrorScreen.java | 2 +- .../net/minecraft/client/gui/GuiMerchant.java | 2 +- .../minecraft/client/gui/GuiMultiplayer.java | 2 +- .../net/minecraft/client/gui/GuiNewChat.java | 2 +- .../minecraft/client/gui/GuiOptionButton.java | 2 +- .../minecraft/client/gui/GuiOptionSlider.java | 2 +- .../net/minecraft/client/gui/GuiOptions.java | 2 +- .../client/gui/GuiOptionsRowList.java | 2 +- .../minecraft/client/gui/GuiOverlayDebug.java | 57 +- .../client/gui/GuiPageButtonList.java | 21 +- .../client/gui/GuiPlayerTabOverlay.java | 2 +- .../minecraft/client/gui/GuiRenameWorld.java | 2 +- .../net/minecraft/client/gui/GuiRepair.java | 2 +- .../client/gui/GuiResourcePackAvailable.java | 2 +- .../client/gui/GuiResourcePackList.java | 2 +- .../client/gui/GuiResourcePackSelected.java | 2 +- .../net/minecraft/client/gui/GuiScreen.java | 8 +- .../client/gui/GuiScreenAddServer.java | 2 +- .../minecraft/client/gui/GuiScreenBook.java | 2 +- .../client/gui/GuiScreenCustomizePresets.java | 2 +- .../client/gui/GuiScreenOptionsSounds.java | 2 +- .../client/gui/GuiScreenResourcePacks.java | 2 +- .../client/gui/GuiScreenServerList.java | 2 +- .../client/gui/GuiScreenWorking.java | 2 +- .../minecraft/client/gui/GuiSelectWorld.java | 2 +- .../net/minecraft/client/gui/GuiSleepMP.java | 2 +- .../net/minecraft/client/gui/GuiSlider.java | 2 +- .../net/minecraft/client/gui/GuiSlot.java | 2 +- .../minecraft/client/gui/GuiSpectator.java | 2 +- .../minecraft/client/gui/GuiTextField.java | 2 +- .../client/gui/GuiUtilRenderComponents.java | 2 +- .../client/gui/GuiVideoSettings.java | 2 +- .../net/minecraft/client/gui/GuiWinGame.java | 2 +- .../net/minecraft/client/gui/GuiYesNo.java | 2 +- .../client/gui/GuiYesNoCallback.java | 2 +- .../minecraft/client/gui/IProgressMeter.java | 2 +- .../minecraft/client/gui/MapItemRenderer.java | 2 +- .../client/gui/ScaledResolution.java | 2 +- .../client/gui/ScreenChatOptions.java | 2 +- .../client/gui/ServerListEntryNormal.java | 2 +- .../client/gui/ServerSelectionList.java | 2 +- .../gui/achievement/GuiAchievement.java | 2 +- .../gui/achievement/GuiAchievements.java | 2 +- .../client/gui/achievement/GuiStats.java | 6 +- .../gui/inventory/CreativeCrafting.java | 2 +- .../client/gui/inventory/GuiBeacon.java | 2 +- .../client/gui/inventory/GuiBrewingStand.java | 2 +- .../client/gui/inventory/GuiChest.java | 2 +- .../client/gui/inventory/GuiContainer.java | 2 +- .../gui/inventory/GuiContainerCreative.java | 9 +- .../client/gui/inventory/GuiCrafting.java | 2 +- .../client/gui/inventory/GuiDispenser.java | 2 +- .../client/gui/inventory/GuiEditSign.java | 2 +- .../client/gui/inventory/GuiFurnace.java | 2 +- .../client/gui/inventory/GuiInventory.java | 2 +- .../inventory/GuiScreenHorseInventory.java | 2 +- .../gui/spectator/BaseSpectatorGroup.java | 2 +- .../gui/spectator/ISpectatorMenuObject.java | 2 +- .../spectator/ISpectatorMenuRecipient.java | 2 +- .../gui/spectator/ISpectatorMenuView.java | 2 +- .../gui/spectator/PlayerMenuObject.java | 2 +- .../client/gui/spectator/SpectatorMenu.java | 2 +- .../categories/SpectatorDetails.java | 2 +- .../categories/TeleportToPlayer.java | 2 +- .../spectator/categories/TeleportToTeam.java | 2 +- .../client/main/GameConfiguration.java | 2 +- .../java/net/minecraft/client/main/Main.java | 2 +- .../client/model/ModelArmorStand.java | 2 +- .../client/model/ModelArmorStandArmor.java | 2 +- .../minecraft/client/model/ModelBanner.java | 2 +- .../net/minecraft/client/model/ModelBase.java | 2 +- .../net/minecraft/client/model/ModelBat.java | 2 +- .../minecraft/client/model/ModelBiped.java | 2 +- .../minecraft/client/model/ModelBlaze.java | 2 +- .../net/minecraft/client/model/ModelBoat.java | 2 +- .../net/minecraft/client/model/ModelBook.java | 2 +- .../net/minecraft/client/model/ModelBox.java | 2 +- .../minecraft/client/model/ModelChest.java | 2 +- .../minecraft/client/model/ModelChicken.java | 2 +- .../net/minecraft/client/model/ModelCow.java | 2 +- .../minecraft/client/model/ModelCreeper.java | 2 +- .../minecraft/client/model/ModelDragon.java | 2 +- .../client/model/ModelEnderCrystal.java | 2 +- .../client/model/ModelEnderMite.java | 2 +- .../minecraft/client/model/ModelEnderman.java | 2 +- .../minecraft/client/model/ModelGhast.java | 2 +- .../minecraft/client/model/ModelGuardian.java | 2 +- .../minecraft/client/model/ModelHorse.java | 2 +- .../client/model/ModelHumanoidHead.java | 2 +- .../client/model/ModelIronGolem.java | 2 +- .../client/model/ModelLargeChest.java | 2 +- .../client/model/ModelLeashKnot.java | 2 +- .../client/model/ModelMagmaCube.java | 2 +- .../minecraft/client/model/ModelMinecart.java | 2 +- .../minecraft/client/model/ModelOcelot.java | 2 +- .../net/minecraft/client/model/ModelPig.java | 2 +- .../minecraft/client/model/ModelPlayer.java | 2 +- .../client/model/ModelQuadruped.java | 2 +- .../minecraft/client/model/ModelRabbit.java | 2 +- .../minecraft/client/model/ModelRenderer.java | 2 +- .../minecraft/client/model/ModelSheep1.java | 2 +- .../minecraft/client/model/ModelSheep2.java | 2 +- .../net/minecraft/client/model/ModelSign.java | 2 +- .../client/model/ModelSilverfish.java | 2 +- .../minecraft/client/model/ModelSkeleton.java | 2 +- .../client/model/ModelSkeletonHead.java | 2 +- .../minecraft/client/model/ModelSlime.java | 2 +- .../minecraft/client/model/ModelSnowMan.java | 2 +- .../minecraft/client/model/ModelSpider.java | 2 +- .../minecraft/client/model/ModelSquid.java | 2 +- .../minecraft/client/model/ModelVillager.java | 2 +- .../minecraft/client/model/ModelWitch.java | 2 +- .../minecraft/client/model/ModelWither.java | 2 +- .../net/minecraft/client/model/ModelWolf.java | 2 +- .../minecraft/client/model/ModelZombie.java | 2 +- .../client/model/ModelZombieVillager.java | 2 +- .../client/model/PositionTextureVertex.java | 2 +- .../minecraft/client/model/TextureOffset.java | 2 +- .../minecraft/client/model/TexturedQuad.java | 2 +- .../multiplayer/ChunkProviderClient.java | 13 +- .../client/multiplayer/GuiConnecting.java | 2 +- .../multiplayer/PlayerControllerMP.java | 2 +- .../client/multiplayer/ServerAddress.java | 2 +- .../client/multiplayer/ServerData.java | 2 +- .../client/multiplayer/ServerList.java | 2 +- .../client/multiplayer/WorldClient.java | 31 +- .../client/network/NetHandlerPlayClient.java | 10 +- .../client/network/NetworkPlayerInfo.java | 2 +- .../minecraft/client/particle/Barrier.java | 2 +- .../client/particle/EffectRenderer.java | 13 +- .../client/particle/EntityAuraFX.java | 2 +- .../client/particle/EntityBlockDustFX.java | 2 +- .../client/particle/EntityBreakingFX.java | 2 +- .../client/particle/EntityBubbleFX.java | 2 +- .../client/particle/EntityCloudFX.java | 2 +- .../client/particle/EntityCrit2FX.java | 2 +- .../client/particle/EntityCritFX.java | 2 +- .../client/particle/EntityDiggingFX.java | 2 +- .../client/particle/EntityDropParticleFX.java | 2 +- .../EntityEnchantmentTableParticleFX.java | 2 +- .../client/particle/EntityExplodeFX.java | 2 +- .../minecraft/client/particle/EntityFX.java | 2 +- .../client/particle/EntityFirework.java | 2 +- .../client/particle/EntityFishWakeFX.java | 2 +- .../client/particle/EntityFlameFX.java | 2 +- .../client/particle/EntityFootStepFX.java | 2 +- .../client/particle/EntityHeartFX.java | 2 +- .../client/particle/EntityHugeExplodeFX.java | 2 +- .../client/particle/EntityLargeExplodeFX.java | 2 +- .../client/particle/EntityLavaFX.java | 2 +- .../client/particle/EntityNoteFX.java | 2 +- .../particle/EntityParticleEmitter.java | 2 +- .../client/particle/EntityPickupFX.java | 2 +- .../client/particle/EntityPortalFX.java | 2 +- .../client/particle/EntityRainFX.java | 2 +- .../client/particle/EntityReddustFX.java | 2 +- .../client/particle/EntitySmokeFX.java | 2 +- .../client/particle/EntitySnowShovelFX.java | 2 +- .../particle/EntitySpellParticleFX.java | 2 +- .../client/particle/EntitySplashFX.java | 2 +- .../client/particle/EntitySuspendFX.java | 2 +- .../client/particle/IParticleFactory.java | 2 +- .../client/particle/MobAppearance.java | 2 +- .../player/inventory/ContainerLocalMenu.java | 16 +- .../LocalBlockIntercommunication.java | 2 +- .../client/renderer/ActiveRenderInfo.java | 2 +- .../client/renderer/BlockFluidRenderer.java | 2 +- .../client/renderer/BlockModelRenderer.java | 2 +- .../client/renderer/BlockModelShapes.java | 2 +- .../renderer/BlockRendererDispatcher.java | 2 +- .../client/renderer/ChestRenderer.java | 2 +- .../client/renderer/ChunkRenderContainer.java | 2 +- .../client/renderer/DestroyBlockProgress.java | 2 +- .../client/renderer/EntityRenderer.java | 7 +- .../client/renderer/EnumFaceDirection.java | 2 +- .../client/renderer/GLAllocation.java | 2 +- .../client/renderer/IImageBuffer.java | 2 +- .../client/renderer/ImageBufferDownload.java | 2 +- .../renderer/InventoryEffectRenderer.java | 10 +- .../client/renderer/ItemMeshDefinition.java | 2 +- .../client/renderer/ItemModelMesher.java | 25 +- .../client/renderer/ItemRenderer.java | 4 +- .../client/renderer/RegionRenderCache.java | 112 +- .../renderer/RegionRenderCacheBuilder.java | 2 +- .../client/renderer/RenderGlobal.java | 2 +- .../client/renderer/RenderHelper.java | 2 +- .../minecraft/client/renderer/RenderList.java | 2 +- .../client/renderer/StitcherException.java | 2 +- .../client/renderer/Tessellator.java | 2 +- .../client/renderer/ViewFrustum.java | 2 +- .../renderer/block/model/BakedQuad.java | 2 +- .../renderer/block/model/BlockFaceUV.java | 2 +- .../renderer/block/model/BlockPart.java | 2 +- .../renderer/block/model/BlockPartFace.java | 2 +- .../block/model/BlockPartRotation.java | 2 +- .../renderer/block/model/BreakingFour.java | 2 +- .../renderer/block/model/FaceBakery.java | 2 +- .../block/model/ItemCameraTransforms.java | 2 +- .../block/model/ItemModelGenerator.java | 2 +- .../block/model/ItemTransformVec3f.java | 2 +- .../renderer/block/model/ModelBlock.java | 2 +- .../block/model/ModelBlockDefinition.java | 2 +- .../block/statemap/BlockStateMapper.java | 2 +- .../block/statemap/DefaultStateMapper.java | 2 +- .../renderer/block/statemap/IStateMapper.java | 2 +- .../renderer/block/statemap/StateMap.java | 2 +- .../block/statemap/StateMapperBase.java | 2 +- .../chunk/ChunkCompileTaskGenerator.java | 2 +- .../renderer/chunk/ChunkRenderWorker.java | 2 +- .../client/renderer/chunk/CompiledChunk.java | 2 +- .../renderer/chunk/IRenderChunkFactory.java | 2 +- .../renderer/chunk/ListChunkFactory.java | 2 +- .../renderer/chunk/ListedRenderChunk.java | 2 +- .../client/renderer/chunk/RenderChunk.java | 23 +- .../client/renderer/chunk/SetVisibility.java | 2 +- .../client/renderer/chunk/VisGraph.java | 2 +- .../renderer/culling/ClippingHelper.java | 2 +- .../renderer/culling/ClippingHelperImpl.java | 2 +- .../client/renderer/culling/Frustum.java | 2 +- .../client/renderer/culling/ICamera.java | 2 +- .../renderer/entity/ArmorStandRenderer.java | 2 +- .../client/renderer/entity/Render.java | 2 +- .../client/renderer/entity/RenderArrow.java | 2 +- .../client/renderer/entity/RenderBat.java | 2 +- .../client/renderer/entity/RenderBiped.java | 2 +- .../client/renderer/entity/RenderBlaze.java | 2 +- .../client/renderer/entity/RenderBoat.java | 2 +- .../renderer/entity/RenderCaveSpider.java | 2 +- .../client/renderer/entity/RenderChicken.java | 2 +- .../client/renderer/entity/RenderCow.java | 2 +- .../client/renderer/entity/RenderCreeper.java | 2 +- .../client/renderer/entity/RenderDragon.java | 2 +- .../renderer/entity/RenderEnderman.java | 2 +- .../renderer/entity/RenderEndermite.java | 2 +- .../client/renderer/entity/RenderEntity.java | 2 +- .../renderer/entity/RenderEntityItem.java | 2 +- .../renderer/entity/RenderFallingBlock.java | 2 +- .../renderer/entity/RenderFireball.java | 2 +- .../client/renderer/entity/RenderFish.java | 2 +- .../client/renderer/entity/RenderGhast.java | 2 +- .../renderer/entity/RenderGiantZombie.java | 2 +- .../renderer/entity/RenderGuardian.java | 2 +- .../client/renderer/entity/RenderHorse.java | 2 +- .../renderer/entity/RenderIronGolem.java | 2 +- .../client/renderer/entity/RenderItem.java | 2 +- .../renderer/entity/RenderLeashKnot.java | 2 +- .../renderer/entity/RenderLightningBolt.java | 2 +- .../client/renderer/entity/RenderLiving.java | 2 +- .../renderer/entity/RenderMagmaCube.java | 2 +- .../client/renderer/entity/RenderManager.java | 2 +- .../renderer/entity/RenderMinecart.java | 2 +- .../entity/RenderMinecartMobSpawner.java | 2 +- .../renderer/entity/RenderMooshroom.java | 2 +- .../client/renderer/entity/RenderOcelot.java | 2 +- .../renderer/entity/RenderPainting.java | 2 +- .../client/renderer/entity/RenderPig.java | 2 +- .../renderer/entity/RenderPigZombie.java | 2 +- .../client/renderer/entity/RenderPlayer.java | 2 +- .../client/renderer/entity/RenderPotion.java | 2 +- .../client/renderer/entity/RenderRabbit.java | 2 +- .../client/renderer/entity/RenderSheep.java | 2 +- .../renderer/entity/RenderSilverfish.java | 2 +- .../renderer/entity/RenderSkeleton.java | 2 +- .../client/renderer/entity/RenderSlime.java | 2 +- .../client/renderer/entity/RenderSnowMan.java | 2 +- .../renderer/entity/RenderSnowball.java | 2 +- .../client/renderer/entity/RenderSpider.java | 2 +- .../client/renderer/entity/RenderSquid.java | 2 +- .../renderer/entity/RenderTNTPrimed.java | 2 +- .../renderer/entity/RenderTntMinecart.java | 2 +- .../renderer/entity/RenderVillager.java | 2 +- .../client/renderer/entity/RenderWitch.java | 2 +- .../client/renderer/entity/RenderWither.java | 2 +- .../client/renderer/entity/RenderWolf.java | 2 +- .../client/renderer/entity/RenderXPOrb.java | 2 +- .../client/renderer/entity/RenderZombie.java | 2 +- .../renderer/entity/RendererLivingEntity.java | 2 +- .../entity/layers/LayerArmorBase.java | 2 +- .../renderer/entity/layers/LayerArrow.java | 2 +- .../entity/layers/LayerBipedArmor.java | 2 +- .../renderer/entity/layers/LayerCape.java | 2 +- .../entity/layers/LayerCreeperCharge.java | 2 +- .../entity/layers/LayerCustomHead.java | 2 +- .../entity/layers/LayerDeadmau5Head.java | 2 +- .../entity/layers/LayerEnderDragonDeath.java | 2 +- .../entity/layers/LayerEnderDragonEyes.java | 2 +- .../entity/layers/LayerEndermanEyes.java | 2 +- .../entity/layers/LayerHeldBlock.java | 2 +- .../renderer/entity/layers/LayerHeldItem.java | 2 +- .../entity/layers/LayerHeldItemWitch.java | 2 +- .../entity/layers/LayerIronGolemFlower.java | 2 +- .../entity/layers/LayerMooshroomMushroom.java | 2 +- .../renderer/entity/layers/LayerRenderer.java | 2 +- .../renderer/entity/layers/LayerSaddle.java | 2 +- .../entity/layers/LayerSheepWool.java | 2 +- .../renderer/entity/layers/LayerSlimeGel.java | 2 +- .../entity/layers/LayerSnowmanHead.java | 2 +- .../entity/layers/LayerSpiderEyes.java | 2 +- .../entity/layers/LayerVillagerArmor.java | 2 +- .../entity/layers/LayerWitherAura.java | 2 +- .../entity/layers/LayerWolfCollar.java | 2 +- .../renderer/texture/AbstractTexture.java | 2 +- .../renderer/texture/DynamicTexture.java | 2 +- .../client/renderer/texture/IIconCreator.java | 2 +- .../renderer/texture/ITextureObject.java | 2 +- .../client/renderer/texture/ITickable.java | 2 +- .../texture/ITickableTextureObject.java | 2 +- .../texture/LayeredColorMaskTexture.java | 2 +- .../renderer/texture/LayeredTexture.java | 2 +- .../renderer/texture/SimpleTexture.java | 2 +- .../client/renderer/texture/Stitcher.java | 2 +- .../client/renderer/texture/TextureClock.java | 2 +- .../renderer/texture/TextureCompass.java | 2 +- .../renderer/texture/TextureManager.java | 14 +- .../client/renderer/texture/TextureMap.java | 22 +- .../client/renderer/texture/TextureUtil.java | 2 +- .../tileentity/RenderEnderCrystal.java | 2 +- .../renderer/tileentity/RenderItemFrame.java | 2 +- .../tileentity/RenderWitherSkull.java | 2 +- .../tileentity/TileEntityBannerRenderer.java | 2 +- .../tileentity/TileEntityBeaconRenderer.java | 2 +- .../tileentity/TileEntityChestRenderer.java | 2 +- .../TileEntityEnchantmentTableRenderer.java | 2 +- .../TileEntityEndPortalRenderer.java | 2 +- .../TileEntityEnderChestRenderer.java | 2 +- .../TileEntityItemStackRenderer.java | 2 +- .../TileEntityMobSpawnerRenderer.java | 2 +- .../tileentity/TileEntityPistonRenderer.java | 2 +- .../TileEntityRendererDispatcher.java | 2 +- .../tileentity/TileEntitySignRenderer.java | 2 +- .../tileentity/TileEntitySkullRenderer.java | 2 +- .../tileentity/TileEntitySpecialRenderer.java | 2 +- .../renderer/vertex/DefaultVertexFormats.java | 2 +- .../resources/AbstractResourcePack.java | 2 +- .../client/resources/DefaultPlayerSkin.java | 2 +- .../client/resources/DefaultResourcePack.java | 2 +- .../resources/FallbackResourceManager.java | 2 +- .../resources/FoliageColorReloadListener.java | 2 +- .../resources/GrassColorReloadListener.java | 2 +- .../net/minecraft/client/resources/I18n.java | 2 +- .../resources/IReloadableResourceManager.java | 2 +- .../minecraft/client/resources/IResource.java | 2 +- .../client/resources/IResourceManager.java | 2 +- .../IResourceManagerReloadListener.java | 2 +- .../client/resources/IResourcePack.java | 2 +- .../minecraft/client/resources/Language.java | 2 +- .../client/resources/LanguageManager.java | 2 +- .../minecraft/client/resources/Locale.java | 2 +- .../ResourcePackFileNotFoundException.java | 2 +- .../resources/ResourcePackListEntry.java | 2 +- .../ResourcePackListEntryDefault.java | 2 +- .../resources/ResourcePackListEntryFound.java | 2 +- .../resources/ResourcePackRepository.java | 2 +- .../SimpleReloadableResourceManager.java | 2 +- .../client/resources/SimpleResource.java | 2 +- .../client/resources/data/AnimationFrame.java | 2 +- .../data/AnimationMetadataSection.java | 14 +- .../AnimationMetadataSectionSerializer.java | 2 +- .../data/BaseMetadataSectionSerializer.java | 2 +- .../resources/data/FontMetadataSection.java | 2 +- .../data/FontMetadataSectionSerializer.java | 2 +- .../resources/data/IMetadataSection.java | 2 +- .../data/IMetadataSectionSerializer.java | 2 +- .../resources/data/IMetadataSerializer.java | 2 +- .../data/LanguageMetadataSection.java | 2 +- .../LanguageMetadataSectionSerializer.java | 2 +- .../resources/data/PackMetadataSection.java | 2 +- .../data/PackMetadataSectionSerializer.java | 2 +- .../data/TextureMetadataSection.java | 13 +- .../TextureMetadataSectionSerializer.java | 8 +- .../client/resources/model/BuiltInModel.java | 2 +- .../client/resources/model/IBakedModel.java | 2 +- .../client/resources/model/ModelBakery.java | 12 +- .../client/resources/model/ModelManager.java | 2 +- .../model/ModelResourceLocation.java | 2 +- .../client/resources/model/ModelRotation.java | 15 +- .../resources/model/SimpleBakedModel.java | 2 +- .../resources/model/WeightedBakedModel.java | 2 +- .../client/settings/GameSettings.java | 8 +- .../minecraft/client/settings/KeyBinding.java | 17 +- .../net/minecraft/client/stream/IStream.java | 2 +- .../client/util/JsonBlendingMode.java | 2 +- .../minecraft/client/util/JsonException.java | 2 +- .../net/minecraft/command/CommandBase.java | 25 +- .../minecraft/command/CommandBlockData.java | 2 +- .../command/CommandClearInventory.java | 2 +- .../net/minecraft/command/CommandClone.java | 2 +- .../net/minecraft/command/CommandCompare.java | 2 +- .../command/CommandDefaultGameMode.java | 2 +- .../minecraft/command/CommandDifficulty.java | 2 +- .../net/minecraft/command/CommandEffect.java | 2 +- .../net/minecraft/command/CommandEnchant.java | 2 +- .../minecraft/command/CommandEntityData.java | 2 +- .../minecraft/command/CommandException.java | 2 +- .../minecraft/command/CommandExecuteAt.java | 2 +- .../net/minecraft/command/CommandFill.java | 2 +- .../minecraft/command/CommandGameMode.java | 2 +- .../minecraft/command/CommandGameRule.java | 2 +- .../net/minecraft/command/CommandGive.java | 2 +- .../net/minecraft/command/CommandHandler.java | 2 +- .../net/minecraft/command/CommandHelp.java | 2 +- .../net/minecraft/command/CommandKill.java | 2 +- .../command/CommandNotFoundException.java | 2 +- .../minecraft/command/CommandParticle.java | 2 +- .../minecraft/command/CommandPlaySound.java | 2 +- .../minecraft/command/CommandReplaceItem.java | 42 +- .../minecraft/command/CommandResultStats.java | 2 +- .../minecraft/command/CommandServerKick.java | 2 +- .../command/CommandSetPlayerTimeout.java | 2 +- .../command/CommandSetSpawnpoint.java | 2 +- .../minecraft/command/CommandShowSeed.java | 2 +- .../command/CommandSpreadPlayers.java | 2 +- .../net/minecraft/command/CommandStats.java | 2 +- .../net/minecraft/command/CommandTime.java | 2 +- .../net/minecraft/command/CommandTitle.java | 2 +- .../command/CommandToggleDownfall.java | 2 +- .../net/minecraft/command/CommandTrigger.java | 2 +- .../net/minecraft/command/CommandWeather.java | 2 +- .../minecraft/command/CommandWorldBorder.java | 2 +- .../java/net/minecraft/command/CommandXP.java | 2 +- .../command/EntityNotFoundException.java | 2 +- .../net/minecraft/command/IAdminCommand.java | 2 +- .../java/net/minecraft/command/ICommand.java | 2 +- .../minecraft/command/ICommandManager.java | 2 +- .../net/minecraft/command/ICommandSender.java | 2 +- .../command/NumberInvalidException.java | 2 +- .../command/PlayerNotFoundException.java | 2 +- .../net/minecraft/command/PlayerSelector.java | 2 +- .../command/ServerCommandManager.java | 2 +- .../command/SyntaxErrorException.java | 2 +- .../command/WrongUsageException.java | 2 +- .../command/server/CommandAchievement.java | 2 +- .../command/server/CommandBlockLogic.java | 2 +- .../command/server/CommandBroadcast.java | 2 +- .../command/server/CommandEmote.java | 2 +- .../command/server/CommandListPlayers.java | 2 +- .../command/server/CommandMessage.java | 2 +- .../command/server/CommandMessageRaw.java | 2 +- .../command/server/CommandScoreboard.java | 2 +- .../command/server/CommandSetBlock.java | 2 +- .../server/CommandSetDefaultSpawnpoint.java | 2 +- .../command/server/CommandSummon.java | 2 +- .../command/server/CommandTeleport.java | 2 +- .../command/server/CommandTestFor.java | 2 +- .../command/server/CommandTestForBlock.java | 2 +- .../java/net/minecraft/crash/CrashReport.java | 2 +- .../minecraft/crash/CrashReportCategory.java | 2 +- .../minecraft/creativetab/CreativeTabs.java | 2 +- .../BehaviorDefaultDispenseItem.java | 2 +- .../dispenser/BehaviorProjectileDispense.java | 2 +- .../dispenser/IBehaviorDispenseItem.java | 2 +- .../net/minecraft/dispenser/IBlockSource.java | 2 +- .../minecraft/dispenser/ILocatableSource.java | 2 +- .../net/minecraft/dispenser/ILocation.java | 2 +- .../net/minecraft/dispenser/IPosition.java | 2 +- .../net/minecraft/dispenser/PositionImpl.java | 2 +- .../minecraft/enchantment/Enchantment.java | 2 +- .../enchantment/EnchantmentArrowDamage.java | 2 +- .../enchantment/EnchantmentArrowFire.java | 2 +- .../enchantment/EnchantmentArrowInfinite.java | 2 +- .../EnchantmentArrowKnockback.java | 2 +- .../enchantment/EnchantmentDamage.java | 2 +- .../enchantment/EnchantmentData.java | 2 +- .../enchantment/EnchantmentDigging.java | 2 +- .../enchantment/EnchantmentDurability.java | 2 +- .../enchantment/EnchantmentFireAspect.java | 2 +- .../enchantment/EnchantmentFishingSpeed.java | 2 +- .../enchantment/EnchantmentHelper.java | 22 +- .../enchantment/EnchantmentKnockback.java | 2 +- .../enchantment/EnchantmentLootBonus.java | 2 +- .../enchantment/EnchantmentOxygen.java | 2 +- .../enchantment/EnchantmentProtection.java | 2 +- .../enchantment/EnchantmentThorns.java | 2 +- .../enchantment/EnchantmentUntouching.java | 2 +- .../enchantment/EnchantmentWaterWalker.java | 2 +- .../enchantment/EnchantmentWaterWorker.java | 2 +- .../enchantment/EnumEnchantmentType.java | 2 +- .../net/minecraft/entity/DataWatcher.java | 59 +- .../java/net/minecraft/entity/Entity.java | 2 +- .../net/minecraft/entity/EntityAgeable.java | 2 +- .../minecraft/entity/EntityBodyHelper.java | 2 +- .../net/minecraft/entity/EntityCreature.java | 2 +- .../net/minecraft/entity/EntityFlying.java | 2 +- .../net/minecraft/entity/EntityHanging.java | 2 +- .../net/minecraft/entity/EntityLeashKnot.java | 2 +- .../java/net/minecraft/entity/EntityList.java | 50 +- .../net/minecraft/entity/EntityLiving.java | 2 +- .../minecraft/entity/EntityLivingBase.java | 76 +- .../entity/EntityMinecartCommandBlock.java | 2 +- .../entity/EntitySpawnPlacementRegistry.java | 2 +- .../net/minecraft/entity/EntityTracker.java | 44 +- .../minecraft/entity/EntityTrackerEntry.java | 30 +- .../entity/EnumCreatureAttribute.java | 2 +- .../minecraft/entity/EnumCreatureType.java | 2 +- .../minecraft/entity/IEntityLivingData.java | 2 +- .../minecraft/entity/IEntityMultiPart.java | 2 +- .../net/minecraft/entity/IEntityOwnable.java | 2 +- .../java/net/minecraft/entity/IMerchant.java | 2 +- src/game/java/net/minecraft/entity/INpc.java | 2 +- .../net/minecraft/entity/IProjectile.java | 2 +- .../minecraft/entity/IRangedAttackMob.java | 2 +- .../net/minecraft/entity/NpcMerchant.java | 2 +- .../entity/SharedMonsterAttributes.java | 2 +- .../entity/ai/EntityAIArrowAttack.java | 2 +- .../entity/ai/EntityAIAttackOnCollide.java | 2 +- .../entity/ai/EntityAIAvoidEntity.java | 2 +- .../net/minecraft/entity/ai/EntityAIBase.java | 2 +- .../net/minecraft/entity/ai/EntityAIBeg.java | 2 +- .../entity/ai/EntityAIBreakDoor.java | 2 +- .../entity/ai/EntityAIControlledByPlayer.java | 2 +- .../entity/ai/EntityAICreeperSwell.java | 2 +- .../entity/ai/EntityAIDefendVillage.java | 2 +- .../entity/ai/EntityAIDoorInteract.java | 2 +- .../minecraft/entity/ai/EntityAIEatGrass.java | 2 +- .../entity/ai/EntityAIFindEntityNearest.java | 2 +- .../ai/EntityAIFindEntityNearestPlayer.java | 2 +- .../minecraft/entity/ai/EntityAIFleeSun.java | 2 +- .../entity/ai/EntityAIFollowGolem.java | 2 +- .../entity/ai/EntityAIFollowOwner.java | 2 +- .../entity/ai/EntityAIFollowParent.java | 2 +- .../entity/ai/EntityAIHarvestFarmland.java | 2 +- .../entity/ai/EntityAIHurtByTarget.java | 2 +- .../entity/ai/EntityAILeapAtTarget.java | 2 +- .../entity/ai/EntityAILookAtTradePlayer.java | 2 +- .../entity/ai/EntityAILookAtVillager.java | 2 +- .../minecraft/entity/ai/EntityAILookIdle.java | 2 +- .../net/minecraft/entity/ai/EntityAIMate.java | 2 +- .../entity/ai/EntityAIMoveIndoors.java | 2 +- .../entity/ai/EntityAIMoveThroughVillage.java | 2 +- .../entity/ai/EntityAIMoveToBlock.java | 2 +- .../ai/EntityAIMoveTowardsRestriction.java | 2 +- .../entity/ai/EntityAIMoveTowardsTarget.java | 2 +- .../ai/EntityAINearestAttackableTarget.java | 2 +- .../entity/ai/EntityAIOcelotAttack.java | 2 +- .../entity/ai/EntityAIOcelotSit.java | 2 +- .../minecraft/entity/ai/EntityAIOpenDoor.java | 2 +- .../entity/ai/EntityAIOwnerHurtByTarget.java | 2 +- .../entity/ai/EntityAIOwnerHurtTarget.java | 2 +- .../minecraft/entity/ai/EntityAIPanic.java | 2 +- .../net/minecraft/entity/ai/EntityAIPlay.java | 2 +- .../entity/ai/EntityAIRestrictOpenDoor.java | 2 +- .../entity/ai/EntityAIRestrictSun.java | 2 +- .../entity/ai/EntityAIRunAroundLikeCrazy.java | 2 +- .../net/minecraft/entity/ai/EntityAISit.java | 2 +- .../minecraft/entity/ai/EntityAISwimming.java | 2 +- .../minecraft/entity/ai/EntityAITarget.java | 2 +- .../entity/ai/EntityAITargetNonTamed.java | 2 +- .../minecraft/entity/ai/EntityAITasks.java | 2 +- .../minecraft/entity/ai/EntityAITempt.java | 2 +- .../entity/ai/EntityAITradePlayer.java | 2 +- .../entity/ai/EntityAIVillagerInteract.java | 2 +- .../entity/ai/EntityAIVillagerMate.java | 2 +- .../minecraft/entity/ai/EntityAIWander.java | 2 +- .../entity/ai/EntityAIWatchClosest.java | 2 +- .../entity/ai/EntityAIWatchClosest2.java | 2 +- .../minecraft/entity/ai/EntityJumpHelper.java | 2 +- .../minecraft/entity/ai/EntityLookHelper.java | 2 +- .../entity/ai/EntityMinecartMobSpawner.java | 2 +- .../minecraft/entity/ai/EntityMoveHelper.java | 2 +- .../net/minecraft/entity/ai/EntitySenses.java | 2 +- .../entity/ai/RandomPositionGenerator.java | 2 +- .../ai/attributes/AttributeModifier.java | 2 +- .../entity/ai/attributes/BaseAttribute.java | 2 +- .../ai/attributes/BaseAttributeMap.java | 2 +- .../entity/ai/attributes/IAttribute.java | 2 +- .../ai/attributes/IAttributeInstance.java | 2 +- .../ModifiableAttributeInstance.java | 14 +- .../entity/ai/attributes/RangedAttribute.java | 2 +- .../ai/attributes/ServersideAttributeMap.java | 2 +- .../net/minecraft/entity/boss/BossStatus.java | 2 +- .../minecraft/entity/boss/EntityDragon.java | 2 +- .../entity/boss/EntityDragonPart.java | 2 +- .../minecraft/entity/boss/EntityWither.java | 2 +- .../entity/boss/IBossDisplayData.java | 2 +- .../entity/effect/EntityLightningBolt.java | 2 +- .../entity/effect/EntityWeatherEffect.java | 2 +- .../entity/item/EntityArmorStand.java | 2 +- .../net/minecraft/entity/item/EntityBoat.java | 2 +- .../entity/item/EntityEnderCrystal.java | 2 +- .../minecraft/entity/item/EntityEnderEye.java | 2 +- .../entity/item/EntityEnderPearl.java | 2 +- .../entity/item/EntityExpBottle.java | 2 +- .../entity/item/EntityFallingBlock.java | 2 +- .../entity/item/EntityFireworkRocket.java | 2 +- .../net/minecraft/entity/item/EntityItem.java | 2 +- .../entity/item/EntityItemFrame.java | 2 +- .../minecraft/entity/item/EntityMinecart.java | 15 +- .../entity/item/EntityMinecartChest.java | 2 +- .../entity/item/EntityMinecartContainer.java | 2 +- .../entity/item/EntityMinecartEmpty.java | 2 +- .../entity/item/EntityMinecartFurnace.java | 2 +- .../entity/item/EntityMinecartHopper.java | 2 +- .../entity/item/EntityMinecartTNT.java | 2 +- .../minecraft/entity/item/EntityPainting.java | 2 +- .../entity/item/EntityTNTPrimed.java | 2 +- .../minecraft/entity/item/EntityXPOrb.java | 2 +- .../minecraft/entity/monster/EntityBlaze.java | 2 +- .../entity/monster/EntityCaveSpider.java | 2 +- .../entity/monster/EntityCreeper.java | 2 +- .../entity/monster/EntityEnderman.java | 11 +- .../entity/monster/EntityEndermite.java | 2 +- .../minecraft/entity/monster/EntityGhast.java | 2 +- .../entity/monster/EntityGiantZombie.java | 2 +- .../minecraft/entity/monster/EntityGolem.java | 2 +- .../entity/monster/EntityGuardian.java | 2 +- .../entity/monster/EntityIronGolem.java | 2 +- .../entity/monster/EntityMagmaCube.java | 2 +- .../minecraft/entity/monster/EntityMob.java | 2 +- .../entity/monster/EntityPigZombie.java | 2 +- .../entity/monster/EntitySilverfish.java | 2 +- .../entity/monster/EntitySkeleton.java | 2 +- .../minecraft/entity/monster/EntitySlime.java | 2 +- .../entity/monster/EntitySnowman.java | 2 +- .../entity/monster/EntitySpider.java | 2 +- .../minecraft/entity/monster/EntityWitch.java | 2 +- .../entity/monster/EntityZombie.java | 2 +- .../net/minecraft/entity/monster/IMob.java | 2 +- .../entity/passive/EntityAmbientCreature.java | 2 +- .../entity/passive/EntityAnimal.java | 2 +- .../minecraft/entity/passive/EntityBat.java | 2 +- .../entity/passive/EntityChicken.java | 2 +- .../minecraft/entity/passive/EntityCow.java | 2 +- .../minecraft/entity/passive/EntityHorse.java | 2 +- .../entity/passive/EntityMooshroom.java | 2 +- .../entity/passive/EntityOcelot.java | 2 +- .../minecraft/entity/passive/EntityPig.java | 2 +- .../entity/passive/EntityRabbit.java | 2 +- .../minecraft/entity/passive/EntitySheep.java | 2 +- .../minecraft/entity/passive/EntitySquid.java | 2 +- .../entity/passive/EntityTameable.java | 2 +- .../entity/passive/EntityVillager.java | 24 +- .../entity/passive/EntityWaterMob.java | 2 +- .../minecraft/entity/passive/EntityWolf.java | 2 +- .../minecraft/entity/passive/IAnimals.java | 2 +- .../minecraft/entity/player/EntityPlayer.java | 2 +- .../entity/player/EntityPlayerMP.java | 64 +- .../entity/player/EnumPlayerModelParts.java | 2 +- .../entity/player/InventoryPlayer.java | 2 +- .../entity/player/PlayerCapabilities.java | 2 +- .../entity/projectile/EntityArrow.java | 2 +- .../entity/projectile/EntityEgg.java | 2 +- .../entity/projectile/EntityFireball.java | 2 +- .../entity/projectile/EntityFishHook.java | 2 +- .../projectile/EntityLargeFireball.java | 2 +- .../entity/projectile/EntityPotion.java | 2 +- .../projectile/EntitySmallFireball.java | 2 +- .../entity/projectile/EntitySnowball.java | 2 +- .../entity/projectile/EntityThrowable.java | 2 +- .../entity/projectile/EntityWitherSkull.java | 2 +- .../java/net/minecraft/event/ClickEvent.java | 2 +- .../java/net/minecraft/event/HoverEvent.java | 2 +- src/game/java/net/minecraft/init/Blocks.java | 2 +- .../java/net/minecraft/init/Bootstrap.java | 2 +- src/game/java/net/minecraft/init/Items.java | 2 +- .../net/minecraft/inventory/AnimalChest.java | 2 +- .../net/minecraft/inventory/Container.java | 2 +- .../minecraft/inventory/ContainerBeacon.java | 2 +- .../inventory/ContainerBrewingStand.java | 2 +- .../minecraft/inventory/ContainerChest.java | 2 +- .../inventory/ContainerDispenser.java | 2 +- .../inventory/ContainerEnchantment.java | 2 +- .../minecraft/inventory/ContainerFurnace.java | 2 +- .../minecraft/inventory/ContainerHopper.java | 2 +- .../inventory/ContainerHorseInventory.java | 2 +- .../inventory/ContainerMerchant.java | 2 +- .../minecraft/inventory/ContainerPlayer.java | 2 +- .../minecraft/inventory/ContainerRepair.java | 32 +- .../inventory/ContainerWorkbench.java | 2 +- .../net/minecraft/inventory/ICrafting.java | 2 +- .../net/minecraft/inventory/IInvBasic.java | 2 +- .../net/minecraft/inventory/IInventory.java | 2 +- .../minecraft/inventory/ISidedInventory.java | 2 +- .../minecraft/inventory/InventoryBasic.java | 2 +- .../inventory/InventoryCraftResult.java | 2 +- .../inventory/InventoryCrafting.java | 2 +- .../inventory/InventoryEnderChest.java | 2 +- .../minecraft/inventory/InventoryHelper.java | 2 +- .../inventory/InventoryLargeChest.java | 2 +- .../inventory/InventoryMerchant.java | 2 +- .../java/net/minecraft/inventory/Slot.java | 2 +- .../net/minecraft/inventory/SlotCrafting.java | 2 +- .../minecraft/inventory/SlotFurnaceFuel.java | 2 +- .../inventory/SlotFurnaceOutput.java | 2 +- .../inventory/SlotMerchantResult.java | 2 +- .../java/net/minecraft/item/EnumAction.java | 2 +- .../java/net/minecraft/item/EnumDyeColor.java | 2 +- .../java/net/minecraft/item/EnumRarity.java | 2 +- src/game/java/net/minecraft/item/Item.java | 2 +- .../net/minecraft/item/ItemAnvilBlock.java | 2 +- .../net/minecraft/item/ItemAppleGold.java | 2 +- .../java/net/minecraft/item/ItemArmor.java | 2 +- .../net/minecraft/item/ItemArmorStand.java | 2 +- src/game/java/net/minecraft/item/ItemAxe.java | 2 +- .../java/net/minecraft/item/ItemBanner.java | 2 +- src/game/java/net/minecraft/item/ItemBed.java | 2 +- .../java/net/minecraft/item/ItemBlock.java | 2 +- .../java/net/minecraft/item/ItemBoat.java | 2 +- .../java/net/minecraft/item/ItemBook.java | 2 +- src/game/java/net/minecraft/item/ItemBow.java | 2 +- .../java/net/minecraft/item/ItemBucket.java | 2 +- .../net/minecraft/item/ItemBucketMilk.java | 2 +- .../minecraft/item/ItemCarrotOnAStick.java | 2 +- .../java/net/minecraft/item/ItemCloth.java | 2 +- .../java/net/minecraft/item/ItemCoal.java | 2 +- .../java/net/minecraft/item/ItemColored.java | 2 +- .../java/net/minecraft/item/ItemDoor.java | 2 +- .../net/minecraft/item/ItemDoublePlant.java | 2 +- src/game/java/net/minecraft/item/ItemDye.java | 2 +- .../net/minecraft/item/ItemEditableBook.java | 2 +- src/game/java/net/minecraft/item/ItemEgg.java | 2 +- .../java/net/minecraft/item/ItemEmptyMap.java | 2 +- .../net/minecraft/item/ItemEnchantedBook.java | 2 +- .../java/net/minecraft/item/ItemEnderEye.java | 2 +- .../net/minecraft/item/ItemEnderPearl.java | 2 +- .../net/minecraft/item/ItemExpBottle.java | 2 +- .../java/net/minecraft/item/ItemFireball.java | 2 +- .../java/net/minecraft/item/ItemFirework.java | 2 +- .../minecraft/item/ItemFireworkCharge.java | 2 +- .../java/net/minecraft/item/ItemFishFood.java | 13 +- .../net/minecraft/item/ItemFishingRod.java | 2 +- .../net/minecraft/item/ItemFlintAndSteel.java | 2 +- .../java/net/minecraft/item/ItemFood.java | 2 +- .../net/minecraft/item/ItemGlassBottle.java | 2 +- .../net/minecraft/item/ItemHangingEntity.java | 2 +- src/game/java/net/minecraft/item/ItemHoe.java | 2 +- .../java/net/minecraft/item/ItemLead.java | 2 +- .../java/net/minecraft/item/ItemLeaves.java | 2 +- .../java/net/minecraft/item/ItemLilyPad.java | 2 +- src/game/java/net/minecraft/item/ItemMap.java | 2 +- .../java/net/minecraft/item/ItemMapBase.java | 2 +- .../java/net/minecraft/item/ItemMinecart.java | 2 +- .../net/minecraft/item/ItemMonsterPlacer.java | 9 +- .../net/minecraft/item/ItemMultiTexture.java | 2 +- .../java/net/minecraft/item/ItemNameTag.java | 2 +- .../java/net/minecraft/item/ItemPickaxe.java | 2 +- .../java/net/minecraft/item/ItemPiston.java | 2 +- .../java/net/minecraft/item/ItemPotion.java | 35 +- .../java/net/minecraft/item/ItemRecord.java | 2 +- .../java/net/minecraft/item/ItemRedstone.java | 2 +- .../java/net/minecraft/item/ItemReed.java | 2 +- .../java/net/minecraft/item/ItemSaddle.java | 2 +- .../java/net/minecraft/item/ItemSeedFood.java | 2 +- .../java/net/minecraft/item/ItemSeeds.java | 2 +- .../java/net/minecraft/item/ItemShears.java | 2 +- .../java/net/minecraft/item/ItemSign.java | 2 +- .../net/minecraft/item/ItemSimpleFoiled.java | 2 +- .../java/net/minecraft/item/ItemSkull.java | 2 +- .../java/net/minecraft/item/ItemSlab.java | 2 +- .../java/net/minecraft/item/ItemSnow.java | 2 +- .../java/net/minecraft/item/ItemSnowball.java | 2 +- .../java/net/minecraft/item/ItemSoup.java | 2 +- .../java/net/minecraft/item/ItemSpade.java | 2 +- .../java/net/minecraft/item/ItemStack.java | 2 +- .../java/net/minecraft/item/ItemSword.java | 2 +- .../java/net/minecraft/item/ItemTool.java | 2 +- .../net/minecraft/item/ItemWritableBook.java | 2 +- .../item/crafting/CraftingManager.java | 2 +- .../item/crafting/FurnaceRecipes.java | 19 +- .../net/minecraft/item/crafting/IRecipe.java | 2 +- .../item/crafting/RecipeBookCloning.java | 2 +- .../item/crafting/RecipeFireworks.java | 2 +- .../item/crafting/RecipeRepairItem.java | 2 +- .../minecraft/item/crafting/RecipesArmor.java | 2 +- .../item/crafting/RecipesArmorDyes.java | 2 +- .../item/crafting/RecipesBanners.java | 2 +- .../item/crafting/RecipesCrafting.java | 2 +- .../minecraft/item/crafting/RecipesDyes.java | 2 +- .../minecraft/item/crafting/RecipesFood.java | 2 +- .../item/crafting/RecipesIngots.java | 2 +- .../item/crafting/RecipesMapCloning.java | 2 +- .../item/crafting/RecipesMapExtending.java | 2 +- .../minecraft/item/crafting/RecipesTools.java | 2 +- .../item/crafting/RecipesWeapons.java | 2 +- .../item/crafting/ShapedRecipes.java | 2 +- .../item/crafting/ShapelessRecipes.java | 2 +- .../minecraft/nbt/CompressedStreamTools.java | 2 +- .../java/net/minecraft/nbt/JsonToNBT.java | 2 +- src/game/java/net/minecraft/nbt/NBTBase.java | 2 +- .../java/net/minecraft/nbt/NBTException.java | 2 +- .../net/minecraft/nbt/NBTSizeTracker.java | 2 +- .../java/net/minecraft/nbt/NBTTagByte.java | 2 +- .../net/minecraft/nbt/NBTTagByteArray.java | 2 +- .../net/minecraft/nbt/NBTTagCompound.java | 2 +- .../java/net/minecraft/nbt/NBTTagDouble.java | 2 +- .../java/net/minecraft/nbt/NBTTagEnd.java | 2 +- .../java/net/minecraft/nbt/NBTTagFloat.java | 2 +- .../java/net/minecraft/nbt/NBTTagInt.java | 2 +- .../net/minecraft/nbt/NBTTagIntArray.java | 2 +- .../java/net/minecraft/nbt/NBTTagList.java | 2 +- .../java/net/minecraft/nbt/NBTTagLong.java | 2 +- .../java/net/minecraft/nbt/NBTTagShort.java | 2 +- .../java/net/minecraft/nbt/NBTTagString.java | 2 +- src/game/java/net/minecraft/nbt/NBTUtil.java | 2 +- .../network/EnumConnectionState.java | 2 +- .../network/EnumPacketDirection.java | 2 +- .../net/minecraft/network/INetHandler.java | 2 +- .../network/NetHandlerPlayServer.java | 19 +- .../java/net/minecraft/network/Packet.java | 2 +- .../net/minecraft/network/PacketBuffer.java | 2 +- .../network/ServerStatusResponse.java | 2 +- .../handshake/INetHandlerHandshakeServer.java | 2 +- .../handshake/client/C00Handshake.java | 2 +- .../network/login/INetHandlerLoginClient.java | 2 +- .../network/login/INetHandlerLoginServer.java | 2 +- .../login/client/C00PacketLoginStart.java | 2 +- .../client/C01PacketEncryptionResponse.java | 2 +- .../login/server/S00PacketDisconnect.java | 2 +- .../server/S01PacketEncryptionRequest.java | 2 +- .../login/server/S02PacketLoginSuccess.java | 2 +- .../server/S03PacketEnableCompression.java | 2 +- .../network/play/INetHandlerPlayClient.java | 2 +- .../network/play/INetHandlerPlayServer.java | 2 +- .../play/client/C00PacketKeepAlive.java | 2 +- .../play/client/C01PacketChatMessage.java | 2 +- .../play/client/C02PacketUseEntity.java | 2 +- .../network/play/client/C03PacketPlayer.java | 2 +- .../play/client/C07PacketPlayerDigging.java | 2 +- .../client/C08PacketPlayerBlockPlacement.java | 2 +- .../play/client/C09PacketHeldItemChange.java | 2 +- .../play/client/C0APacketAnimation.java | 2 +- .../play/client/C0BPacketEntityAction.java | 2 +- .../network/play/client/C0CPacketInput.java | 2 +- .../play/client/C0DPacketCloseWindow.java | 2 +- .../play/client/C0EPacketClickWindow.java | 2 +- .../client/C0FPacketConfirmTransaction.java | 2 +- .../C10PacketCreativeInventoryAction.java | 2 +- .../play/client/C11PacketEnchantItem.java | 2 +- .../play/client/C12PacketUpdateSign.java | 2 +- .../play/client/C13PacketPlayerAbilities.java | 2 +- .../play/client/C14PacketTabComplete.java | 2 +- .../play/client/C15PacketClientSettings.java | 2 +- .../play/client/C16PacketClientStatus.java | 2 +- .../play/client/C17PacketCustomPayload.java | 2 +- .../play/client/C18PacketSpectate.java | 2 +- .../client/C19PacketResourcePackStatus.java | 2 +- .../play/server/S00PacketKeepAlive.java | 2 +- .../play/server/S01PacketJoinGame.java | 2 +- .../network/play/server/S02PacketChat.java | 2 +- .../play/server/S03PacketTimeUpdate.java | 2 +- .../play/server/S04PacketEntityEquipment.java | 2 +- .../play/server/S05PacketSpawnPosition.java | 2 +- .../play/server/S06PacketUpdateHealth.java | 2 +- .../network/play/server/S07PacketRespawn.java | 2 +- .../play/server/S08PacketPlayerPosLook.java | 2 +- .../play/server/S09PacketHeldItemChange.java | 2 +- .../network/play/server/S0APacketUseBed.java | 2 +- .../play/server/S0BPacketAnimation.java | 2 +- .../play/server/S0CPacketSpawnPlayer.java | 2 +- .../play/server/S0DPacketCollectItem.java | 2 +- .../play/server/S0EPacketSpawnObject.java | 2 +- .../play/server/S0FPacketSpawnMob.java | 2 +- .../play/server/S10PacketSpawnPainting.java | 2 +- .../server/S11PacketSpawnExperienceOrb.java | 2 +- .../play/server/S12PacketEntityVelocity.java | 2 +- .../play/server/S13PacketDestroyEntities.java | 2 +- .../network/play/server/S14PacketEntity.java | 2 +- .../play/server/S18PacketEntityTeleport.java | 2 +- .../play/server/S19PacketEntityHeadLook.java | 2 +- .../play/server/S19PacketEntityStatus.java | 2 +- .../play/server/S1BPacketEntityAttach.java | 2 +- .../play/server/S1CPacketEntityMetadata.java | 2 +- .../play/server/S1DPacketEntityEffect.java | 2 +- .../server/S1EPacketRemoveEntityEffect.java | 2 +- .../play/server/S1FPacketSetExperience.java | 2 +- .../server/S20PacketEntityProperties.java | 2 +- .../play/server/S21PacketChunkData.java | 2 +- .../server/S22PacketMultiBlockChange.java | 2 +- .../play/server/S23PacketBlockChange.java | 2 +- .../play/server/S24PacketBlockAction.java | 2 +- .../play/server/S25PacketBlockBreakAnim.java | 2 +- .../play/server/S26PacketMapChunkBulk.java | 2 +- .../play/server/S27PacketExplosion.java | 2 +- .../network/play/server/S28PacketEffect.java | 2 +- .../play/server/S29PacketSoundEffect.java | 2 +- .../play/server/S2APacketParticles.java | 2 +- .../play/server/S2BPacketChangeGameState.java | 2 +- .../server/S2CPacketSpawnGlobalEntity.java | 2 +- .../play/server/S2DPacketOpenWindow.java | 2 +- .../play/server/S2EPacketCloseWindow.java | 2 +- .../network/play/server/S2FPacketSetSlot.java | 2 +- .../play/server/S30PacketWindowItems.java | 2 +- .../play/server/S31PacketWindowProperty.java | 2 +- .../server/S32PacketConfirmTransaction.java | 2 +- .../play/server/S33PacketUpdateSign.java | 2 +- .../network/play/server/S34PacketMaps.java | 2 +- .../server/S35PacketUpdateTileEntity.java | 2 +- .../play/server/S36PacketSignEditorOpen.java | 2 +- .../play/server/S37PacketStatistics.java | 24 +- .../play/server/S38PacketPlayerListItem.java | 2 +- .../play/server/S39PacketPlayerAbilities.java | 2 +- .../play/server/S3APacketTabComplete.java | 2 +- .../server/S3BPacketScoreboardObjective.java | 2 +- .../play/server/S3CPacketUpdateScore.java | 2 +- .../server/S3DPacketDisplayScoreboard.java | 2 +- .../network/play/server/S3EPacketTeams.java | 2 +- .../play/server/S3FPacketCustomPayload.java | 2 +- .../play/server/S40PacketDisconnect.java | 2 +- .../server/S41PacketServerDifficulty.java | 2 +- .../play/server/S42PacketCombatEvent.java | 2 +- .../network/play/server/S43PacketCamera.java | 2 +- .../play/server/S44PacketWorldBorder.java | 2 +- .../network/play/server/S45PacketTitle.java | 2 +- .../server/S46PacketSetCompressionLevel.java | 2 +- .../S47PacketPlayerListHeaderFooter.java | 2 +- .../server/S48PacketResourcePackSend.java | 2 +- .../play/server/S49PacketUpdateEntityNBT.java | 2 +- .../java/net/minecraft/pathfinding/Path.java | 2 +- .../net/minecraft/pathfinding/PathEntity.java | 2 +- .../net/minecraft/pathfinding/PathFinder.java | 2 +- .../minecraft/pathfinding/PathNavigate.java | 24 +- .../pathfinding/PathNavigateClimber.java | 2 +- .../pathfinding/PathNavigateGround.java | 2 +- .../pathfinding/PathNavigateSwimmer.java | 2 +- .../net/minecraft/pathfinding/PathPoint.java | 2 +- .../java/net/minecraft/potion/Potion.java | 2 +- .../minecraft/potion/PotionAbsorption.java | 2 +- .../minecraft/potion/PotionAttackDamage.java | 2 +- .../net/minecraft/potion/PotionEffect.java | 2 +- .../net/minecraft/potion/PotionHealth.java | 2 +- .../minecraft/potion/PotionHealthBoost.java | 2 +- .../net/minecraft/potion/PotionHelper.java | 87 +- .../net/minecraft/scoreboard/GoalColor.java | 2 +- .../scoreboard/IScoreObjectiveCriteria.java | 2 +- .../java/net/minecraft/scoreboard/Score.java | 2 +- .../scoreboard/ScoreDummyCriteria.java | 2 +- .../scoreboard/ScoreHealthCriteria.java | 2 +- .../minecraft/scoreboard/ScoreObjective.java | 2 +- .../minecraft/scoreboard/ScorePlayerTeam.java | 2 +- .../net/minecraft/scoreboard/Scoreboard.java | 2 +- .../scoreboard/ScoreboardSaveData.java | 2 +- .../scoreboard/ServerScoreboard.java | 2 +- .../java/net/minecraft/scoreboard/Team.java | 2 +- .../net/minecraft/server/MinecraftServer.java | 2 +- .../server/management/ItemInWorldManager.java | 2 +- .../server/management/LowerStringMap.java | 2 +- .../server/management/PlayerManager.java | 35 +- .../ServerConfigurationManager.java | 14 +- .../server/network/NetHandlerLoginServer.java | 2 +- .../java/net/minecraft/stats/Achievement.java | 2 +- .../net/minecraft/stats/AchievementList.java | 2 +- .../minecraft/stats/IStatStringFormat.java | 2 +- .../java/net/minecraft/stats/IStatType.java | 2 +- .../net/minecraft/stats/ObjectiveStat.java | 2 +- .../java/net/minecraft/stats/StatBase.java | 2 +- .../java/net/minecraft/stats/StatBasic.java | 2 +- .../net/minecraft/stats/StatCrafting.java | 2 +- .../net/minecraft/stats/StatFileWriter.java | 2 +- .../java/net/minecraft/stats/StatList.java | 2 +- .../net/minecraft/stats/StatisticsFile.java | 12 +- .../net/minecraft/tileentity/IHopper.java | 2 +- .../tileentity/MobSpawnerBaseLogic.java | 2 +- .../net/minecraft/tileentity/TileEntity.java | 2 +- .../tileentity/TileEntityBanner.java | 2 +- .../tileentity/TileEntityBeacon.java | 2 +- .../tileentity/TileEntityBrewingStand.java | 2 +- .../minecraft/tileentity/TileEntityChest.java | 2 +- .../tileentity/TileEntityCommandBlock.java | 2 +- .../tileentity/TileEntityComparator.java | 2 +- .../TileEntityDaylightDetector.java | 2 +- .../tileentity/TileEntityDispenser.java | 2 +- .../tileentity/TileEntityDropper.java | 2 +- .../TileEntityEnchantmentTable.java | 2 +- .../tileentity/TileEntityEndPortal.java | 2 +- .../tileentity/TileEntityEnderChest.java | 2 +- .../tileentity/TileEntityFlowerPot.java | 2 +- .../tileentity/TileEntityFurnace.java | 2 +- .../tileentity/TileEntityHopper.java | 2 +- .../tileentity/TileEntityLockable.java | 2 +- .../tileentity/TileEntityMobSpawner.java | 2 +- .../minecraft/tileentity/TileEntityNote.java | 2 +- .../tileentity/TileEntityPiston.java | 2 +- .../minecraft/tileentity/TileEntitySign.java | 2 +- .../minecraft/tileentity/TileEntitySkull.java | 2 +- .../net/minecraft/util/AxisAlignedBB.java | 2 +- .../java/net/minecraft/util/BlockPos.java | 2 +- .../java/net/minecraft/util/Cartesian.java | 2 +- .../minecraft/util/ChatAllowedCharacters.java | 2 +- .../util/ChatComponentProcessor.java | 2 +- .../minecraft/util/ChatComponentScore.java | 2 +- .../minecraft/util/ChatComponentSelector.java | 2 +- .../minecraft/util/ChatComponentStyle.java | 2 +- .../net/minecraft/util/ChatComponentText.java | 2 +- .../util/ChatComponentTranslation.java | 2 +- ...atComponentTranslationFormatException.java | 2 +- .../java/net/minecraft/util/ChatStyle.java | 2 +- .../util/ClassInheritanceMultiMap.java | 2 +- .../java/net/minecraft/util/CombatEntry.java | 2 +- .../net/minecraft/util/CombatTracker.java | 2 +- .../java/net/minecraft/util/DamageSource.java | 2 +- .../minecraft/util/EnchantmentNameParts.java | 2 +- .../minecraft/util/EntityDamageSource.java | 2 +- .../util/EntityDamageSourceIndirect.java | 2 +- .../net/minecraft/util/EntitySelectors.java | 2 +- .../minecraft/util/EnumChatFormatting.java | 2 +- .../java/net/minecraft/util/EnumFacing.java | 2 +- .../net/minecraft/util/EnumParticleTypes.java | 10 +- .../minecraft/util/EnumWorldBlockLayer.java | 2 +- .../java/net/minecraft/util/FoodStats.java | 2 +- .../java/net/minecraft/util/FrameTimer.java | 2 +- .../net/minecraft/util/IChatComponent.java | 2 +- .../net/minecraft/util/IJsonSerializable.java | 2 +- .../minecraft/util/IObjectIntIterable.java | 2 +- .../net/minecraft/util/IProgressUpdate.java | 2 +- .../java/net/minecraft/util/IRegistry.java | 2 +- .../minecraft/util/IStringSerializable.java | 2 +- .../net/minecraft/util/IThreadListener.java | 2 +- .../java/net/minecraft/util/ITickable.java | 2 +- .../java/net/minecraft/util/IntHashMap.java | 265 - .../java/net/minecraft/util/IntegerCache.java | 2 +- .../minecraft/util/JsonSerializableSet.java | 2 +- .../java/net/minecraft/util/LazyLoadBase.java | 2 +- .../minecraft/util/LoggingPrintStream.java | 2 +- .../java/net/minecraft/util/LongHashMap.java | 269 - .../java/net/minecraft/util/MapPopulator.java | 2 +- .../java/net/minecraft/util/MathHelper.java | 2 +- .../java/net/minecraft/util/Matrix4f.java | 2 +- .../net/minecraft/util/MinecraftError.java | 2 +- .../java/net/minecraft/util/MouseFilter.java | 2 +- .../java/net/minecraft/util/MouseHelper.java | 2 +- .../net/minecraft/util/MovementInput.java | 2 +- .../util/MovementInputFromOptions.java | 2 +- .../minecraft/util/MovingObjectPosition.java | 2 +- .../minecraft/util/ObjectIntIdentityMap.java | 11 +- .../net/minecraft/util/RegistryDefaulted.java | 2 +- .../minecraft/util/RegistryNamespaced.java | 2 +- .../RegistryNamespacedDefaultedByKey.java | 2 +- .../net/minecraft/util/RegistrySimple.java | 2 +- .../net/minecraft/util/ReportedException.java | 2 +- .../net/minecraft/util/ResourceLocation.java | 2 +- .../java/net/minecraft/util/Rotations.java | 2 +- .../net/minecraft/util/ScreenShotHelper.java | 2 +- src/game/java/net/minecraft/util/Session.java | 2 +- .../net/minecraft/util/StatCollector.java | 2 +- .../net/minecraft/util/StringTranslate.java | 2 +- .../java/net/minecraft/util/StringUtils.java | 2 +- src/game/java/net/minecraft/util/Timer.java | 2 +- src/game/java/net/minecraft/util/Tuple.java | 2 +- .../util/TupleIntJsonSerializable.java | 2 +- src/game/java/net/minecraft/util/Util.java | 2 +- src/game/java/net/minecraft/util/Vec3.java | 2 +- src/game/java/net/minecraft/util/Vec3i.java | 2 +- src/game/java/net/minecraft/util/Vec4b.java | 2 +- .../java/net/minecraft/util/Vector3d.java | 2 +- .../net/minecraft/util/WeightedRandom.java | 2 +- .../util/WeightedRandomChestContent.java | 2 +- .../util/WeightedRandomFishable.java | 2 +- .../net/minecraft/village/MerchantRecipe.java | 2 +- .../minecraft/village/MerchantRecipeList.java | 2 +- .../java/net/minecraft/village/Village.java | 30 +- .../minecraft/village/VillageCollection.java | 2 +- .../minecraft/village/VillageDoorInfo.java | 2 +- .../net/minecraft/village/VillageSiege.java | 2 +- .../java/net/minecraft/world/ChunkCache.java | 6 +- .../minecraft/world/ChunkCoordIntPair.java | 2 +- .../net/minecraft/world/ColorizerFoliage.java | 2 +- .../net/minecraft/world/ColorizerGrass.java | 2 +- .../minecraft/world/DifficultyInstance.java | 2 +- .../net/minecraft/world/EnumDifficulty.java | 2 +- .../net/minecraft/world/EnumSkyBlock.java | 2 +- .../java/net/minecraft/world/Explosion.java | 2 +- .../java/net/minecraft/world/GameRules.java | 2 +- .../net/minecraft/world/IBlockAccess.java | 4 +- .../minecraft/world/IInteractionObject.java | 2 +- .../minecraft/world/ILockableContainer.java | 2 +- .../net/minecraft/world/IWorldAccess.java | 2 +- .../net/minecraft/world/IWorldNameable.java | 2 +- .../java/net/minecraft/world/LockCode.java | 2 +- .../minecraft/world/NextTickListEntry.java | 2 +- .../net/minecraft/world/SpawnerAnimals.java | 27 +- .../java/net/minecraft/world/Teleporter.java | 33 +- src/game/java/net/minecraft/world/World.java | 69 +- .../net/minecraft/world/WorldManager.java | 2 +- .../net/minecraft/world/WorldProvider.java | 2 +- .../net/minecraft/world/WorldProviderEnd.java | 2 +- .../minecraft/world/WorldProviderHell.java | 2 +- .../minecraft/world/WorldProviderSurface.java | 2 +- .../net/minecraft/world/WorldSavedData.java | 2 +- .../java/net/minecraft/world/WorldServer.java | 50 +- .../net/minecraft/world/WorldServerMulti.java | 2 +- .../net/minecraft/world/WorldSettings.java | 2 +- .../java/net/minecraft/world/WorldType.java | 2 +- .../net/minecraft/world/biome/BiomeCache.java | 13 +- .../world/biome/BiomeColorHelper.java | 19 +- .../minecraft/world/biome/BiomeDecorator.java | 2 +- .../world/biome/BiomeEndDecorator.java | 2 +- .../minecraft/world/biome/BiomeGenBase.java | 2 +- .../minecraft/world/biome/BiomeGenBeach.java | 2 +- .../minecraft/world/biome/BiomeGenDesert.java | 2 +- .../minecraft/world/biome/BiomeGenEnd.java | 2 +- .../minecraft/world/biome/BiomeGenForest.java | 2 +- .../minecraft/world/biome/BiomeGenHell.java | 2 +- .../minecraft/world/biome/BiomeGenHills.java | 2 +- .../minecraft/world/biome/BiomeGenJungle.java | 2 +- .../minecraft/world/biome/BiomeGenMesa.java | 2 +- .../world/biome/BiomeGenMushroomIsland.java | 2 +- .../world/biome/BiomeGenMutated.java | 2 +- .../minecraft/world/biome/BiomeGenOcean.java | 2 +- .../minecraft/world/biome/BiomeGenPlains.java | 2 +- .../minecraft/world/biome/BiomeGenRiver.java | 2 +- .../world/biome/BiomeGenSavanna.java | 2 +- .../minecraft/world/biome/BiomeGenSnow.java | 2 +- .../world/biome/BiomeGenStoneBeach.java | 2 +- .../minecraft/world/biome/BiomeGenSwamp.java | 2 +- .../minecraft/world/biome/BiomeGenTaiga.java | 2 +- .../world/biome/WorldChunkManager.java | 9 +- .../world/biome/WorldChunkManagerHell.java | 2 +- .../world/border/EnumBorderStatus.java | 2 +- .../world/border/IBorderListener.java | 2 +- .../minecraft/world/border/WorldBorder.java | 9 +- .../java/net/minecraft/world/chunk/Chunk.java | 159 +- .../minecraft/world/chunk/ChunkPrimer.java | 2 +- .../net/minecraft/world/chunk/EmptyChunk.java | 2 +- .../minecraft/world/chunk/IChunkProvider.java | 2 +- .../minecraft/world/chunk/NibbleArray.java | 16 +- .../world/chunk/storage/AnvilChunkLoader.java | 2 +- .../world/chunk/storage/ChunkLoader.java | 2 +- .../chunk/storage/ExtendedBlockStorage.java | 2 +- .../world/chunk/storage/IChunkLoader.java | 2 +- .../chunk/storage/NibbleArrayReader.java | 2 +- .../world/chunk/storage/RegionFile.java | 2 +- .../world/demo/DemoWorldManager.java | 2 +- .../minecraft/world/demo/DemoWorldServer.java | 2 +- .../world/gen/ChunkProviderDebug.java | 2 +- .../minecraft/world/gen/ChunkProviderEnd.java | 2 +- .../world/gen/ChunkProviderFlat.java | 2 +- .../world/gen/ChunkProviderGenerate.java | 2 +- .../world/gen/ChunkProviderHell.java | 2 +- .../world/gen/ChunkProviderServer.java | 42 +- .../world/gen/ChunkProviderSettings.java | 2 +- .../world/gen/FlatGeneratorInfo.java | 2 +- .../minecraft/world/gen/FlatLayerInfo.java | 2 +- .../world/gen/GeneratorBushFeature.java | 2 +- .../net/minecraft/world/gen/MapGenBase.java | 2 +- .../net/minecraft/world/gen/MapGenCaves.java | 2 +- .../minecraft/world/gen/MapGenCavesHell.java | 2 +- .../net/minecraft/world/gen/MapGenRavine.java | 2 +- .../minecraft/world/gen/NoiseGenerator.java | 2 +- .../world/gen/NoiseGeneratorImproved.java | 2 +- .../world/gen/NoiseGeneratorOctaves.java | 2 +- .../world/gen/NoiseGeneratorPerlin.java | 2 +- .../world/gen/NoiseGeneratorSimplex.java | 2 +- .../gen/feature/WorldGenAbstractTree.java | 2 +- .../gen/feature/WorldGenBigMushroom.java | 2 +- .../world/gen/feature/WorldGenBigTree.java | 2 +- .../world/gen/feature/WorldGenBlockBlob.java | 2 +- .../world/gen/feature/WorldGenCactus.java | 2 +- .../world/gen/feature/WorldGenCanopyTree.java | 2 +- .../world/gen/feature/WorldGenClay.java | 2 +- .../world/gen/feature/WorldGenDeadBush.java | 2 +- .../gen/feature/WorldGenDesertWells.java | 2 +- .../gen/feature/WorldGenDoublePlant.java | 2 +- .../world/gen/feature/WorldGenDungeons.java | 2 +- .../world/gen/feature/WorldGenFire.java | 2 +- .../world/gen/feature/WorldGenFlowers.java | 2 +- .../world/gen/feature/WorldGenForest.java | 2 +- .../world/gen/feature/WorldGenGlowStone1.java | 2 +- .../world/gen/feature/WorldGenGlowStone2.java | 2 +- .../world/gen/feature/WorldGenHellLava.java | 2 +- .../world/gen/feature/WorldGenHugeTrees.java | 2 +- .../world/gen/feature/WorldGenIcePath.java | 2 +- .../world/gen/feature/WorldGenIceSpike.java | 2 +- .../world/gen/feature/WorldGenLakes.java | 2 +- .../world/gen/feature/WorldGenLiquids.java | 2 +- .../world/gen/feature/WorldGenMegaJungle.java | 2 +- .../gen/feature/WorldGenMegaPineTree.java | 2 +- .../world/gen/feature/WorldGenMelon.java | 2 +- .../world/gen/feature/WorldGenMinable.java | 2 +- .../world/gen/feature/WorldGenPumpkin.java | 2 +- .../world/gen/feature/WorldGenReed.java | 2 +- .../world/gen/feature/WorldGenSand.java | 2 +- .../gen/feature/WorldGenSavannaTree.java | 2 +- .../world/gen/feature/WorldGenShrub.java | 2 +- .../world/gen/feature/WorldGenSpikes.java | 2 +- .../world/gen/feature/WorldGenSwamp.java | 2 +- .../world/gen/feature/WorldGenTaiga1.java | 2 +- .../world/gen/feature/WorldGenTaiga2.java | 2 +- .../world/gen/feature/WorldGenTallGrass.java | 2 +- .../world/gen/feature/WorldGenTrees.java | 2 +- .../world/gen/feature/WorldGenVines.java | 2 +- .../world/gen/feature/WorldGenWaterlily.java | 2 +- .../world/gen/feature/WorldGenerator.java | 2 +- .../gen/feature/WorldGeneratorBonusChest.java | 2 +- .../minecraft/world/gen/layer/GenLayer.java | 13 +- .../world/gen/layer/GenLayerAddIsland.java | 2 +- .../gen/layer/GenLayerAddMushroomIsland.java | 2 +- .../world/gen/layer/GenLayerAddSnow.java | 2 +- .../world/gen/layer/GenLayerBiome.java | 2 +- .../world/gen/layer/GenLayerBiomeEdge.java | 2 +- .../world/gen/layer/GenLayerDeepOcean.java | 2 +- .../world/gen/layer/GenLayerEdge.java | 2 +- .../world/gen/layer/GenLayerFuzzyZoom.java | 2 +- .../world/gen/layer/GenLayerHills.java | 2 +- .../world/gen/layer/GenLayerIsland.java | 2 +- .../world/gen/layer/GenLayerRareBiome.java | 2 +- .../gen/layer/GenLayerRemoveTooMuchOcean.java | 2 +- .../world/gen/layer/GenLayerRiver.java | 2 +- .../world/gen/layer/GenLayerRiverInit.java | 2 +- .../world/gen/layer/GenLayerRiverMix.java | 2 +- .../world/gen/layer/GenLayerShore.java | 2 +- .../world/gen/layer/GenLayerSmooth.java | 2 +- .../world/gen/layer/GenLayerVoronoiZoom.java | 2 +- .../world/gen/layer/GenLayerZoom.java | 2 +- .../minecraft/world/gen/layer/IntCache.java | 2 +- .../ComponentScatteredFeaturePieces.java | 2 +- .../world/gen/structure/MapGenMineshaft.java | 2 +- .../gen/structure/MapGenNetherBridge.java | 2 +- .../gen/structure/MapGenScatteredFeature.java | 2 +- .../world/gen/structure/MapGenStronghold.java | 2 +- .../world/gen/structure/MapGenStructure.java | 34 +- .../gen/structure/MapGenStructureData.java | 2 +- .../gen/structure/MapGenStructureIO.java | 2 +- .../world/gen/structure/MapGenVillage.java | 2 +- .../gen/structure/StructureBoundingBox.java | 2 +- .../gen/structure/StructureComponent.java | 2 +- .../structure/StructureMineshaftPieces.java | 2 +- .../structure/StructureMineshaftStart.java | 2 +- .../StructureNetherBridgePieces.java | 2 +- .../gen/structure/StructureOceanMonument.java | 2 +- .../StructureOceanMonumentPieces.java | 2 +- .../world/gen/structure/StructureStart.java | 2 +- .../structure/StructureStrongholdPieces.java | 2 +- .../gen/structure/StructureVillagePieces.java | 2 +- .../world/pathfinder/NodeProcessor.java | 14 +- .../world/pathfinder/SwimNodeProcessor.java | 2 +- .../world/pathfinder/WalkNodeProcessor.java | 2 +- .../world/storage/DerivedWorldInfo.java | 2 +- .../world/storage/IPlayerFileData.java | 2 +- .../minecraft/world/storage/ISaveFormat.java | 2 +- .../minecraft/world/storage/ISaveHandler.java | 2 +- .../net/minecraft/world/storage/MapData.java | 2 +- .../minecraft/world/storage/MapStorage.java | 2 +- .../world/storage/SaveDataMemoryStorage.java | 2 +- .../world/storage/SaveFormatComparator.java | 2 +- .../world/storage/SaveFormatOld.java | 2 +- .../minecraft/world/storage/SaveHandler.java | 2 +- .../world/storage/SaveHandlerMP.java | 2 +- .../minecraft/world/storage/WorldInfo.java | 2 +- .../v1_8/internal/PlatformRuntime.java | 28 + .../buffer/EaglerLWJGLByteBuffer.java | 4 +- .../buffer/EaglerLWJGLFloatBuffer.java | 4 +- .../internal/buffer/EaglerLWJGLIntBuffer.java | 4 +- .../buffer/EaglerLWJGLShortBuffer.java | 4 +- .../hppc/AbstractByteCollection.java | 51 + .../hppc/AbstractCharCollection.java | 51 + .../hppc/AbstractDoubleCollection.java | 51 + .../hppc/AbstractFloatCollection.java | 51 + .../hppc/AbstractIntCollection.java | 50 + .../carrotsearch/hppc/AbstractIterator.java | 71 + .../hppc/AbstractLongCollection.java | 51 + .../hppc/AbstractObjectCollection.java | 66 + .../hppc/AbstractShortCollection.java | 51 + .../com/carrotsearch/hppc/Accountable.java | 31 + .../hppc/ArraySizingStrategy.java | 27 + .../java/com/carrotsearch/hppc/BitMixer.java | 120 + .../java/com/carrotsearch/hppc/BitSet.java | 952 ++++ .../com/carrotsearch/hppc/BitSetIterator.java | 356 ++ .../java/com/carrotsearch/hppc/BitUtil.java | 98 + ...oundedProportionalArraySizingStrategy.java | 115 + .../hppc/BufferAllocationException.java | 41 + .../com/carrotsearch/hppc/ByteArrayDeque.java | 776 +++ .../com/carrotsearch/hppc/ByteArrayList.java | 579 ++ .../hppc/ByteBufferVisualizer.java | 33 + .../com/carrotsearch/hppc/ByteCollection.java | 64 + .../com/carrotsearch/hppc/ByteContainer.java | 76 + .../java/com/carrotsearch/hppc/ByteDeque.java | 77 + .../hppc/ByteIndexedContainer.java | 91 + .../hppc/ByteLookupContainer.java | 12 + .../java/com/carrotsearch/hppc/ByteStack.java | 137 + .../com/carrotsearch/hppc/CharArrayDeque.java | 776 +++ .../com/carrotsearch/hppc/CharArrayList.java | 579 ++ .../hppc/CharBufferVisualizer.java | 33 + .../hppc/CharByteAssociativeContainer.java | 105 + .../carrotsearch/hppc/CharByteHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/CharByteMap.java | 205 + .../hppc/CharCharAssociativeContainer.java | 105 + .../carrotsearch/hppc/CharCharHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/CharCharMap.java | 205 + .../com/carrotsearch/hppc/CharCollection.java | 64 + .../com/carrotsearch/hppc/CharContainer.java | 76 + .../java/com/carrotsearch/hppc/CharDeque.java | 77 + .../hppc/CharDoubleAssociativeContainer.java | 105 + .../carrotsearch/hppc/CharDoubleHashMap.java | 1082 ++++ .../com/carrotsearch/hppc/CharDoubleMap.java | 205 + .../hppc/CharFloatAssociativeContainer.java | 105 + .../carrotsearch/hppc/CharFloatHashMap.java | 1081 ++++ .../com/carrotsearch/hppc/CharFloatMap.java | 205 + .../com/carrotsearch/hppc/CharHashSet.java | 787 +++ .../hppc/CharIndexedContainer.java | 91 + .../hppc/CharIntAssociativeContainer.java | 105 + .../com/carrotsearch/hppc/CharIntHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/CharIntMap.java | 205 + .../hppc/CharLongAssociativeContainer.java | 105 + .../carrotsearch/hppc/CharLongHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/CharLongMap.java | 205 + .../hppc/CharLookupContainer.java | 12 + .../hppc/CharObjectAssociativeContainer.java | 105 + .../carrotsearch/hppc/CharObjectHashMap.java | 1050 ++++ .../com/carrotsearch/hppc/CharObjectMap.java | 181 + .../java/com/carrotsearch/hppc/CharSet.java | 33 + .../hppc/CharShortAssociativeContainer.java | 105 + .../carrotsearch/hppc/CharShortHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/CharShortMap.java | 205 + .../java/com/carrotsearch/hppc/CharStack.java | 137 + .../com/carrotsearch/hppc/Containers.java | 68 + .../carrotsearch/hppc/DoubleArrayDeque.java | 776 +++ .../carrotsearch/hppc/DoubleArrayList.java | 586 ++ .../hppc/DoubleBufferVisualizer.java | 33 + .../carrotsearch/hppc/DoubleCollection.java | 64 + .../carrotsearch/hppc/DoubleContainer.java | 76 + .../com/carrotsearch/hppc/DoubleDeque.java | 77 + .../hppc/DoubleIndexedContainer.java | 93 + .../hppc/DoubleLookupContainer.java | 12 + .../com/carrotsearch/hppc/DoublePgmIndex.java | 600 +++ .../com/carrotsearch/hppc/DoubleStack.java | 137 + .../carrotsearch/hppc/FloatArrayDeque.java | 776 +++ .../com/carrotsearch/hppc/FloatArrayList.java | 579 ++ .../hppc/FloatBufferVisualizer.java | 33 + .../carrotsearch/hppc/FloatCollection.java | 64 + .../com/carrotsearch/hppc/FloatContainer.java | 76 + .../com/carrotsearch/hppc/FloatDeque.java | 77 + .../hppc/FloatIndexedContainer.java | 91 + .../hppc/FloatLookupContainer.java | 12 + .../com/carrotsearch/hppc/FloatPgmIndex.java | 600 +++ .../com/carrotsearch/hppc/FloatStack.java | 137 + .../java/com/carrotsearch/hppc/Generated.java | 37 + .../com/carrotsearch/hppc/HashContainers.java | 112 + .../com/carrotsearch/hppc/IntArrayDeque.java | 776 +++ .../com/carrotsearch/hppc/IntArrayList.java | 586 ++ .../hppc/IntBufferVisualizer.java | 33 + .../hppc/IntByteAssociativeContainer.java | 105 + .../com/carrotsearch/hppc/IntByteHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/IntByteMap.java | 205 + .../hppc/IntCharAssociativeContainer.java | 105 + .../com/carrotsearch/hppc/IntCharHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/IntCharMap.java | 205 + .../com/carrotsearch/hppc/IntCollection.java | 64 + .../com/carrotsearch/hppc/IntContainer.java | 76 + .../java/com/carrotsearch/hppc/IntDeque.java | 77 + .../hppc/IntDoubleAssociativeContainer.java | 105 + .../carrotsearch/hppc/IntDoubleHashMap.java | 1082 ++++ .../com/carrotsearch/hppc/IntDoubleMap.java | 205 + .../hppc/IntFloatAssociativeContainer.java | 105 + .../carrotsearch/hppc/IntFloatHashMap.java | 1081 ++++ .../com/carrotsearch/hppc/IntFloatMap.java | 205 + .../com/carrotsearch/hppc/IntHashSet.java | 787 +++ .../hppc/IntIndexedContainer.java | 93 + .../hppc/IntIntAssociativeContainer.java | 105 + .../com/carrotsearch/hppc/IntIntHashMap.java | 1080 ++++ .../java/com/carrotsearch/hppc/IntIntMap.java | 205 + .../hppc/IntLongAssociativeContainer.java | 105 + .../com/carrotsearch/hppc/IntLongHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/IntLongMap.java | 205 + .../carrotsearch/hppc/IntLookupContainer.java | 12 + .../hppc/IntObjectAssociativeContainer.java | 105 + .../carrotsearch/hppc/IntObjectHashMap.java | 1050 ++++ .../com/carrotsearch/hppc/IntObjectMap.java | 181 + .../com/carrotsearch/hppc/IntPgmIndex.java | 600 +++ .../java/com/carrotsearch/hppc/IntSet.java | 33 + .../hppc/IntShortAssociativeContainer.java | 105 + .../carrotsearch/hppc/IntShortHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/IntShortMap.java | 205 + .../java/com/carrotsearch/hppc/IntStack.java | 137 + .../com/carrotsearch/hppc/LongArrayDeque.java | 776 +++ .../com/carrotsearch/hppc/LongArrayList.java | 586 ++ .../hppc/LongBufferVisualizer.java | 33 + .../hppc/LongByteAssociativeContainer.java | 105 + .../carrotsearch/hppc/LongByteHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/LongByteMap.java | 205 + .../hppc/LongCharAssociativeContainer.java | 105 + .../carrotsearch/hppc/LongCharHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/LongCharMap.java | 205 + .../com/carrotsearch/hppc/LongCollection.java | 64 + .../com/carrotsearch/hppc/LongContainer.java | 76 + .../java/com/carrotsearch/hppc/LongDeque.java | 77 + .../hppc/LongDoubleAssociativeContainer.java | 105 + .../carrotsearch/hppc/LongDoubleHashMap.java | 1082 ++++ .../com/carrotsearch/hppc/LongDoubleMap.java | 205 + .../hppc/LongFloatAssociativeContainer.java | 105 + .../carrotsearch/hppc/LongFloatHashMap.java | 1081 ++++ .../com/carrotsearch/hppc/LongFloatMap.java | 205 + .../com/carrotsearch/hppc/LongHashSet.java | 787 +++ .../hppc/LongIndexedContainer.java | 93 + .../hppc/LongIntAssociativeContainer.java | 105 + .../com/carrotsearch/hppc/LongIntHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/LongIntMap.java | 205 + .../hppc/LongLongAssociativeContainer.java | 105 + .../carrotsearch/hppc/LongLongHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/LongLongMap.java | 205 + .../hppc/LongLookupContainer.java | 12 + .../hppc/LongObjectAssociativeContainer.java | 105 + .../carrotsearch/hppc/LongObjectHashMap.java | 1050 ++++ .../com/carrotsearch/hppc/LongObjectMap.java | 181 + .../com/carrotsearch/hppc/LongPgmIndex.java | 600 +++ .../java/com/carrotsearch/hppc/LongSet.java | 33 + .../hppc/LongShortAssociativeContainer.java | 105 + .../carrotsearch/hppc/LongShortHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/LongShortMap.java | 205 + .../java/com/carrotsearch/hppc/LongStack.java | 137 + .../carrotsearch/hppc/ObjectArrayDeque.java | 786 +++ .../carrotsearch/hppc/ObjectArrayList.java | 604 +++ .../hppc/ObjectBufferVisualizer.java | 33 + .../hppc/ObjectByteAssociativeContainer.java | 105 + .../carrotsearch/hppc/ObjectByteHashMap.java | 1089 ++++ .../hppc/ObjectByteIdentityHashMap.java | 71 + .../com/carrotsearch/hppc/ObjectByteMap.java | 205 + .../hppc/ObjectCharAssociativeContainer.java | 105 + .../carrotsearch/hppc/ObjectCharHashMap.java | 1089 ++++ .../hppc/ObjectCharIdentityHashMap.java | 71 + .../com/carrotsearch/hppc/ObjectCharMap.java | 205 + .../carrotsearch/hppc/ObjectCollection.java | 64 + .../carrotsearch/hppc/ObjectContainer.java | 85 + .../com/carrotsearch/hppc/ObjectDeque.java | 77 + .../ObjectDoubleAssociativeContainer.java | 106 + .../hppc/ObjectDoubleHashMap.java | 1091 ++++ .../hppc/ObjectDoubleIdentityHashMap.java | 71 + .../carrotsearch/hppc/ObjectDoubleMap.java | 205 + .../hppc/ObjectFloatAssociativeContainer.java | 105 + .../carrotsearch/hppc/ObjectFloatHashMap.java | 1090 ++++ .../hppc/ObjectFloatIdentityHashMap.java | 71 + .../com/carrotsearch/hppc/ObjectFloatMap.java | 205 + .../com/carrotsearch/hppc/ObjectHashSet.java | 797 +++ .../hppc/ObjectIdentityHashSet.java | 66 + .../hppc/ObjectIndexedContainer.java | 93 + .../hppc/ObjectIntAssociativeContainer.java | 105 + .../carrotsearch/hppc/ObjectIntHashMap.java | 1089 ++++ .../hppc/ObjectIntIdentityHashMap.java | 71 + .../com/carrotsearch/hppc/ObjectIntMap.java | 205 + .../hppc/ObjectLongAssociativeContainer.java | 105 + .../carrotsearch/hppc/ObjectLongHashMap.java | 1089 ++++ .../hppc/ObjectLongIdentityHashMap.java | 71 + .../com/carrotsearch/hppc/ObjectLongMap.java | 205 + .../hppc/ObjectLookupContainer.java | 12 + .../ObjectObjectAssociativeContainer.java | 106 + .../hppc/ObjectObjectHashMap.java | 1059 ++++ .../hppc/ObjectObjectIdentityHashMap.java | 91 + .../carrotsearch/hppc/ObjectObjectMap.java | 183 + .../java/com/carrotsearch/hppc/ObjectSet.java | 33 + .../hppc/ObjectShortAssociativeContainer.java | 105 + .../carrotsearch/hppc/ObjectShortHashMap.java | 1089 ++++ .../hppc/ObjectShortIdentityHashMap.java | 71 + .../com/carrotsearch/hppc/ObjectShortMap.java | 205 + .../com/carrotsearch/hppc/ObjectStack.java | 145 + .../com/carrotsearch/hppc/PgmIndexUtil.java | 122 + .../java/com/carrotsearch/hppc/PlaModel.java | 414 ++ .../com/carrotsearch/hppc/Preallocable.java | 21 + .../carrotsearch/hppc/RamUsageEstimator.java | 162 + .../carrotsearch/hppc/ShortArrayDeque.java | 776 +++ .../com/carrotsearch/hppc/ShortArrayList.java | 579 ++ .../hppc/ShortBufferVisualizer.java | 33 + .../hppc/ShortByteAssociativeContainer.java | 105 + .../carrotsearch/hppc/ShortByteHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/ShortByteMap.java | 205 + .../hppc/ShortCharAssociativeContainer.java | 105 + .../carrotsearch/hppc/ShortCharHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/ShortCharMap.java | 205 + .../carrotsearch/hppc/ShortCollection.java | 64 + .../com/carrotsearch/hppc/ShortContainer.java | 76 + .../com/carrotsearch/hppc/ShortDeque.java | 77 + .../hppc/ShortDoubleAssociativeContainer.java | 105 + .../carrotsearch/hppc/ShortDoubleHashMap.java | 1082 ++++ .../com/carrotsearch/hppc/ShortDoubleMap.java | 205 + .../hppc/ShortFloatAssociativeContainer.java | 105 + .../carrotsearch/hppc/ShortFloatHashMap.java | 1081 ++++ .../com/carrotsearch/hppc/ShortFloatMap.java | 205 + .../com/carrotsearch/hppc/ShortHashSet.java | 787 +++ .../hppc/ShortIndexedContainer.java | 91 + .../hppc/ShortIntAssociativeContainer.java | 105 + .../carrotsearch/hppc/ShortIntHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/ShortIntMap.java | 205 + .../hppc/ShortLongAssociativeContainer.java | 105 + .../carrotsearch/hppc/ShortLongHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/ShortLongMap.java | 205 + .../hppc/ShortLookupContainer.java | 12 + .../hppc/ShortObjectAssociativeContainer.java | 105 + .../carrotsearch/hppc/ShortObjectHashMap.java | 1050 ++++ .../com/carrotsearch/hppc/ShortObjectMap.java | 181 + .../java/com/carrotsearch/hppc/ShortSet.java | 33 + .../hppc/ShortShortAssociativeContainer.java | 105 + .../carrotsearch/hppc/ShortShortHashMap.java | 1080 ++++ .../com/carrotsearch/hppc/ShortShortMap.java | 205 + .../com/carrotsearch/hppc/ShortStack.java | 137 + .../hppc/SortedIterationCharByteHashMap.java | 440 ++ .../hppc/SortedIterationCharCharHashMap.java | 440 ++ .../SortedIterationCharDoubleHashMap.java | 441 ++ .../hppc/SortedIterationCharFloatHashMap.java | 441 ++ .../hppc/SortedIterationCharIntHashMap.java | 440 ++ .../hppc/SortedIterationCharLongHashMap.java | 440 ++ .../SortedIterationCharObjectHashMap.java | 435 ++ .../hppc/SortedIterationCharShortHashMap.java | 441 ++ .../hppc/SortedIterationIntByteHashMap.java | 440 ++ .../hppc/SortedIterationIntCharHashMap.java | 440 ++ .../hppc/SortedIterationIntDoubleHashMap.java | 441 ++ .../hppc/SortedIterationIntFloatHashMap.java | 440 ++ .../hppc/SortedIterationIntIntHashMap.java | 440 ++ .../hppc/SortedIterationIntLongHashMap.java | 440 ++ .../hppc/SortedIterationIntObjectHashMap.java | 435 ++ .../hppc/SortedIterationIntShortHashMap.java | 440 ++ .../hppc/SortedIterationLongByteHashMap.java | 440 ++ .../hppc/SortedIterationLongCharHashMap.java | 440 ++ .../SortedIterationLongDoubleHashMap.java | 441 ++ .../hppc/SortedIterationLongFloatHashMap.java | 441 ++ .../hppc/SortedIterationLongIntHashMap.java | 440 ++ .../hppc/SortedIterationLongLongHashMap.java | 440 ++ .../SortedIterationLongObjectHashMap.java | 435 ++ .../hppc/SortedIterationLongShortHashMap.java | 441 ++ .../SortedIterationObjectByteHashMap.java | 447 ++ .../SortedIterationObjectCharHashMap.java | 447 ++ .../SortedIterationObjectDoubleHashMap.java | 447 ++ .../SortedIterationObjectFloatHashMap.java | 447 ++ .../hppc/SortedIterationObjectIntHashMap.java | 447 ++ .../SortedIterationObjectLongHashMap.java | 447 ++ .../SortedIterationObjectObjectHashMap.java | 440 ++ .../SortedIterationObjectShortHashMap.java | 447 ++ .../hppc/SortedIterationShortByteHashMap.java | 442 ++ .../hppc/SortedIterationShortCharHashMap.java | 442 ++ .../SortedIterationShortDoubleHashMap.java | 443 ++ .../SortedIterationShortFloatHashMap.java | 442 ++ .../hppc/SortedIterationShortIntHashMap.java | 441 ++ .../hppc/SortedIterationShortLongHashMap.java | 442 ++ .../SortedIterationShortObjectHashMap.java | 436 ++ .../SortedIterationShortShortHashMap.java | 442 ++ .../com/carrotsearch/hppc/XorShift128P.java | 67 + .../hppc/comparators/ByteByteComparator.java | 9 + .../hppc/comparators/ByteCharComparator.java | 9 + .../hppc/comparators/ByteComparator.java | 11 + .../comparators/ByteDoubleComparator.java | 9 + .../hppc/comparators/ByteFloatComparator.java | 9 + .../hppc/comparators/ByteIntComparator.java | 9 + .../hppc/comparators/ByteLongComparator.java | 9 + .../comparators/ByteObjectComparator.java | 9 + .../hppc/comparators/ByteShortComparator.java | 9 + .../hppc/comparators/CharByteComparator.java | 9 + .../hppc/comparators/CharCharComparator.java | 9 + .../hppc/comparators/CharComparator.java | 11 + .../comparators/CharDoubleComparator.java | 9 + .../hppc/comparators/CharFloatComparator.java | 9 + .../hppc/comparators/CharIntComparator.java | 9 + .../hppc/comparators/CharLongComparator.java | 9 + .../comparators/CharObjectComparator.java | 9 + .../hppc/comparators/CharShortComparator.java | 9 + .../comparators/DoubleByteComparator.java | 9 + .../comparators/DoubleCharComparator.java | 9 + .../hppc/comparators/DoubleComparator.java | 7 + .../comparators/DoubleDoubleComparator.java | 9 + .../comparators/DoubleFloatComparator.java | 9 + .../hppc/comparators/DoubleIntComparator.java | 9 + .../comparators/DoubleLongComparator.java | 9 + .../comparators/DoubleObjectComparator.java | 9 + .../comparators/DoubleShortComparator.java | 9 + .../hppc/comparators/FloatByteComparator.java | 9 + .../hppc/comparators/FloatCharComparator.java | 9 + .../hppc/comparators/FloatComparator.java | 7 + .../comparators/FloatDoubleComparator.java | 9 + .../comparators/FloatFloatComparator.java | 9 + .../hppc/comparators/FloatIntComparator.java | 9 + .../hppc/comparators/FloatLongComparator.java | 9 + .../comparators/FloatObjectComparator.java | 9 + .../comparators/FloatShortComparator.java | 9 + .../hppc/comparators/IntByteComparator.java | 9 + .../hppc/comparators/IntCharComparator.java | 9 + .../hppc/comparators/IntComparator.java | 11 + .../hppc/comparators/IntDoubleComparator.java | 9 + .../hppc/comparators/IntFloatComparator.java | 9 + .../hppc/comparators/IntIntComparator.java | 9 + .../hppc/comparators/IntLongComparator.java | 9 + .../hppc/comparators/IntObjectComparator.java | 9 + .../hppc/comparators/IntShortComparator.java | 9 + .../hppc/comparators/LongByteComparator.java | 9 + .../hppc/comparators/LongCharComparator.java | 9 + .../hppc/comparators/LongComparator.java | 11 + .../comparators/LongDoubleComparator.java | 9 + .../hppc/comparators/LongFloatComparator.java | 9 + .../hppc/comparators/LongIntComparator.java | 9 + .../hppc/comparators/LongLongComparator.java | 9 + .../comparators/LongObjectComparator.java | 9 + .../hppc/comparators/LongShortComparator.java | 9 + .../comparators/ObjectByteComparator.java | 9 + .../comparators/ObjectCharComparator.java | 9 + .../comparators/ObjectDoubleComparator.java | 9 + .../comparators/ObjectFloatComparator.java | 9 + .../hppc/comparators/ObjectIntComparator.java | 9 + .../comparators/ObjectLongComparator.java | 9 + .../comparators/ObjectObjectComparator.java | 9 + .../comparators/ObjectShortComparator.java | 9 + .../hppc/comparators/ShortByteComparator.java | 9 + .../hppc/comparators/ShortCharComparator.java | 9 + .../hppc/comparators/ShortComparator.java | 11 + .../comparators/ShortDoubleComparator.java | 9 + .../comparators/ShortFloatComparator.java | 9 + .../hppc/comparators/ShortIntComparator.java | 9 + .../hppc/comparators/ShortLongComparator.java | 9 + .../comparators/ShortObjectComparator.java | 9 + .../comparators/ShortShortComparator.java | 9 + .../carrotsearch/hppc/cursors/ByteCursor.java | 19 + .../hppc/cursors/CharByteCursor.java | 23 + .../hppc/cursors/CharCharCursor.java | 23 + .../carrotsearch/hppc/cursors/CharCursor.java | 19 + .../hppc/cursors/CharDoubleCursor.java | 23 + .../hppc/cursors/CharFloatCursor.java | 23 + .../hppc/cursors/CharIntCursor.java | 23 + .../hppc/cursors/CharLongCursor.java | 23 + .../hppc/cursors/CharObjectCursor.java | 23 + .../hppc/cursors/CharShortCursor.java | 23 + .../hppc/cursors/DoubleCursor.java | 19 + .../hppc/cursors/FloatCursor.java | 19 + .../hppc/cursors/IntByteCursor.java | 23 + .../hppc/cursors/IntCharCursor.java | 23 + .../carrotsearch/hppc/cursors/IntCursor.java | 19 + .../hppc/cursors/IntDoubleCursor.java | 23 + .../hppc/cursors/IntFloatCursor.java | 23 + .../hppc/cursors/IntIntCursor.java | 23 + .../hppc/cursors/IntLongCursor.java | 23 + .../hppc/cursors/IntObjectCursor.java | 23 + .../hppc/cursors/IntShortCursor.java | 23 + .../hppc/cursors/LongByteCursor.java | 23 + .../hppc/cursors/LongCharCursor.java | 23 + .../carrotsearch/hppc/cursors/LongCursor.java | 19 + .../hppc/cursors/LongDoubleCursor.java | 23 + .../hppc/cursors/LongFloatCursor.java | 23 + .../hppc/cursors/LongIntCursor.java | 23 + .../hppc/cursors/LongLongCursor.java | 23 + .../hppc/cursors/LongObjectCursor.java | 23 + .../hppc/cursors/LongShortCursor.java | 23 + .../hppc/cursors/ObjectByteCursor.java | 23 + .../hppc/cursors/ObjectCharCursor.java | 23 + .../hppc/cursors/ObjectCursor.java | 19 + .../hppc/cursors/ObjectDoubleCursor.java | 23 + .../hppc/cursors/ObjectFloatCursor.java | 23 + .../hppc/cursors/ObjectIntCursor.java | 23 + .../hppc/cursors/ObjectLongCursor.java | 23 + .../hppc/cursors/ObjectObjectCursor.java | 23 + .../hppc/cursors/ObjectShortCursor.java | 23 + .../hppc/cursors/ShortByteCursor.java | 23 + .../hppc/cursors/ShortCharCursor.java | 23 + .../hppc/cursors/ShortCursor.java | 19 + .../hppc/cursors/ShortDoubleCursor.java | 23 + .../hppc/cursors/ShortFloatCursor.java | 23 + .../hppc/cursors/ShortIntCursor.java | 23 + .../hppc/cursors/ShortLongCursor.java | 23 + .../hppc/cursors/ShortObjectCursor.java | 23 + .../hppc/cursors/ShortShortCursor.java | 23 + .../hppc/internals/SuppressForbidden.java | 20 + .../hppc/predicates/ByteBytePredicate.java | 9 + .../hppc/predicates/ByteCharPredicate.java | 9 + .../hppc/predicates/ByteDoublePredicate.java | 9 + .../hppc/predicates/ByteFloatPredicate.java | 9 + .../hppc/predicates/ByteIntPredicate.java | 9 + .../hppc/predicates/ByteLongPredicate.java | 9 + .../hppc/predicates/ByteObjectPredicate.java | 9 + .../hppc/predicates/BytePredicate.java | 7 + .../hppc/predicates/ByteShortPredicate.java | 9 + .../hppc/predicates/CharBytePredicate.java | 9 + .../hppc/predicates/CharCharPredicate.java | 9 + .../hppc/predicates/CharDoublePredicate.java | 9 + .../hppc/predicates/CharFloatPredicate.java | 9 + .../hppc/predicates/CharIntPredicate.java | 9 + .../hppc/predicates/CharLongPredicate.java | 9 + .../hppc/predicates/CharObjectPredicate.java | 9 + .../hppc/predicates/CharPredicate.java | 7 + .../hppc/predicates/CharShortPredicate.java | 9 + .../hppc/predicates/DoubleBytePredicate.java | 9 + .../hppc/predicates/DoubleCharPredicate.java | 9 + .../predicates/DoubleDoublePredicate.java | 9 + .../hppc/predicates/DoubleFloatPredicate.java | 9 + .../hppc/predicates/DoubleIntPredicate.java | 9 + .../hppc/predicates/DoubleLongPredicate.java | 9 + .../predicates/DoubleObjectPredicate.java | 9 + .../hppc/predicates/DoublePredicate.java | 7 + .../hppc/predicates/DoubleShortPredicate.java | 9 + .../hppc/predicates/FloatBytePredicate.java | 9 + .../hppc/predicates/FloatCharPredicate.java | 9 + .../hppc/predicates/FloatDoublePredicate.java | 9 + .../hppc/predicates/FloatFloatPredicate.java | 9 + .../hppc/predicates/FloatIntPredicate.java | 9 + .../hppc/predicates/FloatLongPredicate.java | 9 + .../hppc/predicates/FloatObjectPredicate.java | 9 + .../hppc/predicates/FloatPredicate.java | 7 + .../hppc/predicates/FloatShortPredicate.java | 9 + .../hppc/predicates/IntBytePredicate.java | 9 + .../hppc/predicates/IntCharPredicate.java | 9 + .../hppc/predicates/IntDoublePredicate.java | 9 + .../hppc/predicates/IntFloatPredicate.java | 9 + .../hppc/predicates/IntIntPredicate.java | 9 + .../hppc/predicates/IntLongPredicate.java | 9 + .../hppc/predicates/IntObjectPredicate.java | 9 + .../hppc/predicates/IntPredicate.java | 7 + .../hppc/predicates/IntShortPredicate.java | 9 + .../hppc/predicates/LongBytePredicate.java | 9 + .../hppc/predicates/LongCharPredicate.java | 9 + .../hppc/predicates/LongDoublePredicate.java | 9 + .../hppc/predicates/LongFloatPredicate.java | 9 + .../hppc/predicates/LongIntPredicate.java | 9 + .../hppc/predicates/LongLongPredicate.java | 9 + .../hppc/predicates/LongObjectPredicate.java | 9 + .../hppc/predicates/LongPredicate.java | 7 + .../hppc/predicates/LongShortPredicate.java | 9 + .../hppc/predicates/ObjectBytePredicate.java | 9 + .../hppc/predicates/ObjectCharPredicate.java | 9 + .../predicates/ObjectDoublePredicate.java | 9 + .../hppc/predicates/ObjectFloatPredicate.java | 9 + .../hppc/predicates/ObjectIntPredicate.java | 9 + .../hppc/predicates/ObjectLongPredicate.java | 9 + .../predicates/ObjectObjectPredicate.java | 9 + .../hppc/predicates/ObjectPredicate.java | 7 + .../hppc/predicates/ObjectShortPredicate.java | 9 + .../hppc/predicates/ShortBytePredicate.java | 9 + .../hppc/predicates/ShortCharPredicate.java | 9 + .../hppc/predicates/ShortDoublePredicate.java | 9 + .../hppc/predicates/ShortFloatPredicate.java | 9 + .../hppc/predicates/ShortIntPredicate.java | 9 + .../hppc/predicates/ShortLongPredicate.java | 9 + .../hppc/predicates/ShortObjectPredicate.java | 9 + .../hppc/predicates/ShortPredicate.java | 7 + .../hppc/predicates/ShortShortPredicate.java | 9 + .../hppc/procedures/ByteByteProcedure.java | 9 + .../hppc/procedures/ByteCharProcedure.java | 9 + .../hppc/procedures/ByteDoubleProcedure.java | 9 + .../hppc/procedures/ByteFloatProcedure.java | 9 + .../hppc/procedures/ByteIntProcedure.java | 9 + .../hppc/procedures/ByteLongProcedure.java | 9 + .../hppc/procedures/ByteObjectProcedure.java | 9 + .../hppc/procedures/ByteProcedure.java | 7 + .../hppc/procedures/ByteShortProcedure.java | 9 + .../hppc/procedures/CharByteProcedure.java | 9 + .../hppc/procedures/CharCharProcedure.java | 9 + .../hppc/procedures/CharDoubleProcedure.java | 9 + .../hppc/procedures/CharFloatProcedure.java | 9 + .../hppc/procedures/CharIntProcedure.java | 9 + .../hppc/procedures/CharLongProcedure.java | 9 + .../hppc/procedures/CharObjectProcedure.java | 9 + .../hppc/procedures/CharProcedure.java | 7 + .../hppc/procedures/CharShortProcedure.java | 9 + .../hppc/procedures/DoubleByteProcedure.java | 9 + .../hppc/procedures/DoubleCharProcedure.java | 9 + .../procedures/DoubleDoubleProcedure.java | 9 + .../hppc/procedures/DoubleFloatProcedure.java | 9 + .../hppc/procedures/DoubleIntProcedure.java | 9 + .../hppc/procedures/DoubleLongProcedure.java | 9 + .../procedures/DoubleObjectProcedure.java | 9 + .../hppc/procedures/DoubleProcedure.java | 7 + .../hppc/procedures/DoubleShortProcedure.java | 9 + .../hppc/procedures/FloatByteProcedure.java | 9 + .../hppc/procedures/FloatCharProcedure.java | 9 + .../hppc/procedures/FloatDoubleProcedure.java | 9 + .../hppc/procedures/FloatFloatProcedure.java | 9 + .../hppc/procedures/FloatIntProcedure.java | 9 + .../hppc/procedures/FloatLongProcedure.java | 9 + .../hppc/procedures/FloatObjectProcedure.java | 9 + .../hppc/procedures/FloatProcedure.java | 7 + .../hppc/procedures/FloatShortProcedure.java | 9 + .../hppc/procedures/IntByteProcedure.java | 9 + .../hppc/procedures/IntCharProcedure.java | 9 + .../hppc/procedures/IntDoubleProcedure.java | 9 + .../hppc/procedures/IntFloatProcedure.java | 9 + .../hppc/procedures/IntIntProcedure.java | 9 + .../hppc/procedures/IntLongProcedure.java | 9 + .../hppc/procedures/IntObjectProcedure.java | 9 + .../hppc/procedures/IntProcedure.java | 7 + .../hppc/procedures/IntShortProcedure.java | 9 + .../hppc/procedures/LongByteProcedure.java | 9 + .../hppc/procedures/LongCharProcedure.java | 9 + .../hppc/procedures/LongDoubleProcedure.java | 9 + .../hppc/procedures/LongFloatProcedure.java | 9 + .../hppc/procedures/LongIntProcedure.java | 9 + .../hppc/procedures/LongLongProcedure.java | 9 + .../hppc/procedures/LongObjectProcedure.java | 9 + .../hppc/procedures/LongProcedure.java | 7 + .../hppc/procedures/LongShortProcedure.java | 9 + .../hppc/procedures/ObjectByteProcedure.java | 9 + .../hppc/procedures/ObjectCharProcedure.java | 9 + .../procedures/ObjectDoubleProcedure.java | 9 + .../hppc/procedures/ObjectFloatProcedure.java | 9 + .../hppc/procedures/ObjectIntProcedure.java | 9 + .../hppc/procedures/ObjectLongProcedure.java | 9 + .../procedures/ObjectObjectProcedure.java | 9 + .../hppc/procedures/ObjectProcedure.java | 7 + .../hppc/procedures/ObjectShortProcedure.java | 9 + .../hppc/procedures/ShortByteProcedure.java | 9 + .../hppc/procedures/ShortCharProcedure.java | 9 + .../hppc/procedures/ShortDoubleProcedure.java | 9 + .../hppc/procedures/ShortFloatProcedure.java | 9 + .../hppc/procedures/ShortIntProcedure.java | 9 + .../hppc/procedures/ShortLongProcedure.java | 9 + .../hppc/procedures/ShortObjectProcedure.java | 9 + .../hppc/procedures/ShortProcedure.java | 7 + .../hppc/procedures/ShortShortProcedure.java | 9 + .../hppc/sorting/IndirectSort.java | 133 + .../carrotsearch/hppc/sorting/QuickSort.java | 181 + .../java/jdk_internal/bidi/Annotation.java | 88 + .../bidi/AttributedCharacterIterator.java | 299 ++ .../jdk_internal/bidi/AttributedString.java | 1109 ++++ src/main/java/jdk_internal/bidi/Bidi.java | 362 ++ .../jdk_internal/bidi/CharacterIterator.java | 203 + .../java/jdk_internal/bidi/Normalizer.java | 178 + .../java/jdk_internal/bidi/NumericShaper.java | 1351 +++++ .../jdk_internal/bidi/ParseException.java | 83 + .../java/jdk_internal/bidi/SunNormalizer.java | 96 + .../java/jdk_internal/bidi/TextAttribute.java | 1065 ++++ .../jdk_internal/bidi/icu/impl/BMPSet.java | 530 ++ .../jdk_internal/bidi/icu/impl/CharTrie.java | 175 + .../icu/impl/CharacterIteratorWrapper.java | 148 + .../jdk_internal/bidi/icu/impl/ICUBinary.java | 303 ++ .../bidi/icu/impl/Norm2AllModes.java | 296 ++ .../bidi/icu/impl/NormalizerImpl.java | 2261 ++++++++ .../jdk_internal/bidi/icu/impl/Punycode.java | 500 ++ .../impl/ReplaceableUCharacterIterator.java | 198 + .../bidi/icu/impl/StringPrepDataReader.java | 120 + .../java/jdk_internal/bidi/icu/impl/Trie.java | 368 ++ .../jdk_internal/bidi/icu/impl/Trie2.java | 652 +++ .../jdk_internal/bidi/icu/impl/Trie2_16.java | 170 + .../bidi/icu/impl/UBiDiProps.java | 270 + .../bidi/icu/impl/UCharacterProperty.java | 627 +++ .../bidi/icu/impl/UnicodeSetStringSpan.java | 1179 ++++ .../jdk_internal/bidi/icu/impl/Utility.java | 266 + .../bidi/icu/lang/UCharacter.java | 562 ++ .../bidi/icu/lang/UCharacterDirection.java | 113 + .../bidi/icu/lang/UCharacterEnums.java | 666 +++ .../jdk_internal/bidi/icu/text/BidiBase.java | 4729 +++++++++++++++++ .../jdk_internal/bidi/icu/text/BidiLine.java | 821 +++ .../jdk_internal/bidi/icu/text/BidiRun.java | 123 + .../bidi/icu/text/BidiWriter.java | 425 ++ .../bidi/icu/text/FilteredNormalizer2.java | 271 + .../bidi/icu/text/Normalizer2.java | 288 + .../bidi/icu/text/NormalizerBase.java | 791 +++ .../bidi/icu/text/Replaceable.java | 124 + .../bidi/icu/text/ReplaceableString.java | 121 + .../bidi/icu/text/StringPrep.java | 493 ++ .../bidi/icu/text/UCharacterIterator.java | 326 ++ .../jdk_internal/bidi/icu/text/UTF16.java | 609 +++ .../bidi/icu/text/UnicodeSet.java | 1515 ++++++ .../bidi/icu/util/CodePointMap.java | 498 ++ .../bidi/icu/util/CodePointTrie.java | 1357 +++++ .../jdk_internal/bidi/icu/util/OutputInt.java | 48 + .../bidi/icu/util/VersionInfo.java | 191 + .../eaglercraft/v1_8/EaglerBidiReorder.java | 87 + .../lax1dude/eaglercraft/v1_8/EaglerZLIB.java | 24 +- .../eaglercraft/v1_8/EaglercraftVersion.java | 8 +- .../v1_8/internal/buffer/ByteBuffer.java | 98 +- .../v1_8/internal/buffer/FloatBuffer.java | 58 +- .../v1_8/internal/buffer/IntBuffer.java | 56 +- .../v1_8/internal/buffer/ShortBuffer.java | 58 +- .../minecraft/EaglerTextureAtlasSprite.java | 8 +- .../v1_8/opengl/EaglerMeshLoader.java | 1 + .../v1_8/opengl/EaglercraftGPU.java | 11 +- .../v1_8/opengl/WorldRenderer.java | 66 +- .../opengl/ext/deferred/BlockVertexIDs.java | 6 +- .../ext/deferred/DebugFramebufferView.java | 8 + .../ext/deferred/EaglerDeferredPipeline.java | 155 +- ...ipelineShaderRealisticWaterNormalsMix.java | 57 + .../program/PipelineShaderReprojSSR.java | 2 + .../ext/deferred/program/ShaderCompiler.java | 12 +- .../program/ShaderMissingException.java | 24 + .../ext/deferred/program/ShaderSource.java | 1 + .../texture/EaglerTextureAtlasSpritePBR.java | 8 +- .../v1_8/profile/ServerSkinCache.java | 2 +- .../v1_8/socket/ServerQueryImpl.java | 1 - .../client/GameProtocolMessageController.java | 7 +- .../v1_8/sp/ipc/IPCPacketManager.java | 6 +- .../v1_8/sp/lan/LANClientNetworkManager.java | 47 +- .../v1_8/sp/server/GenLayerEaglerRivers.java | 107 + .../IntegratedServerPlayerNetworkManager.java | 50 +- .../ClientIntegratedServerNetworkManager.java | 22 +- .../v1_8/touch_gui/TouchControls.java | 9 +- .../v1_8/touch_gui/TouchOverlayRenderer.java | 8 +- .../v1_8/internal/PlatformRuntime.java | 49 +- .../buffer/EaglerArrayByteBuffer.java | 4 +- .../buffer/EaglerArrayFloatBuffer.java | 4 +- .../internal/buffer/EaglerArrayIntBuffer.java | 4 +- .../buffer/EaglerArrayShortBuffer.java | 4 +- src/wasm-gc-teavm-bootstrap/js/main.js | 24 + .../v1_8/internal/PlatformNetworking.java | 14 - .../v1_8/internal/PlatformRuntime.java | 55 +- .../v1_8/internal/PlatformVoiceClient.java | 5 +- .../buffer/DirectMallocByteBuffer.java | 4 +- .../buffer/DirectMallocFloatBuffer.java | 4 +- .../buffer/DirectMallocIntBuffer.java | 4 +- .../buffer/DirectMallocShortBuffer.java | 4 +- .../buffer/WASMGCBufferAllocator.java | 2 +- .../BetterJSStringConverter.java | 2 - .../internal/wasm_gc_teavm/TeaVMUtils.java | 7 - .../wasm_gc_teavm/WASMGCWebSocketClient.java | 1 - .../internal/ServerPlatformSingleplayer.java | 1 - .../wasm_gc_teavm/JS_IPCPacketData.java | 7 +- wasm_gc_teavm/javascript/epw_meta.txt | 6 +- wasm_gc_teavm/javascript_dist/bootstrap.js | 25 +- 2143 files changed, 132267 insertions(+), 3237 deletions(-) create mode 100755 desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_normals_mix.fsh create mode 100755 desktopRuntime/resources/assets/eagler/icudt/nfc.nrm create mode 100755 desktopRuntime/resources/assets/eagler/icudt/nfkc.nrm create mode 100755 desktopRuntime/resources/assets/eagler/icudt/ubidi.icu create mode 100755 desktopRuntime/resources/assets/eagler/icudt/uprops.icu delete mode 100755 src/game/java/net/minecraft/util/IntHashMap.java delete mode 100755 src/game/java/net/minecraft/util/LongHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/AbstractByteCollection.java create mode 100755 src/main/java/com/carrotsearch/hppc/AbstractCharCollection.java create mode 100755 src/main/java/com/carrotsearch/hppc/AbstractDoubleCollection.java create mode 100755 src/main/java/com/carrotsearch/hppc/AbstractFloatCollection.java create mode 100755 src/main/java/com/carrotsearch/hppc/AbstractIntCollection.java create mode 100755 src/main/java/com/carrotsearch/hppc/AbstractIterator.java create mode 100755 src/main/java/com/carrotsearch/hppc/AbstractLongCollection.java create mode 100755 src/main/java/com/carrotsearch/hppc/AbstractObjectCollection.java create mode 100755 src/main/java/com/carrotsearch/hppc/AbstractShortCollection.java create mode 100755 src/main/java/com/carrotsearch/hppc/Accountable.java create mode 100755 src/main/java/com/carrotsearch/hppc/ArraySizingStrategy.java create mode 100755 src/main/java/com/carrotsearch/hppc/BitMixer.java create mode 100755 src/main/java/com/carrotsearch/hppc/BitSet.java create mode 100755 src/main/java/com/carrotsearch/hppc/BitSetIterator.java create mode 100755 src/main/java/com/carrotsearch/hppc/BitUtil.java create mode 100755 src/main/java/com/carrotsearch/hppc/BoundedProportionalArraySizingStrategy.java create mode 100755 src/main/java/com/carrotsearch/hppc/BufferAllocationException.java create mode 100755 src/main/java/com/carrotsearch/hppc/ByteArrayDeque.java create mode 100755 src/main/java/com/carrotsearch/hppc/ByteArrayList.java create mode 100755 src/main/java/com/carrotsearch/hppc/ByteBufferVisualizer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ByteCollection.java create mode 100755 src/main/java/com/carrotsearch/hppc/ByteContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ByteDeque.java create mode 100755 src/main/java/com/carrotsearch/hppc/ByteIndexedContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ByteLookupContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ByteStack.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharArrayDeque.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharArrayList.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharBufferVisualizer.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharByteAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharByteHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharByteMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharCharAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharCharHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharCharMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharCollection.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharDeque.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharDoubleAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharDoubleHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharDoubleMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharFloatAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharFloatHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharFloatMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharHashSet.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharIndexedContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharIntAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharIntHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharIntMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharLongAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharLongHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharLongMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharLookupContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharObjectAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharObjectHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharObjectMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharSet.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharShortAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharShortHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharShortMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/CharStack.java create mode 100755 src/main/java/com/carrotsearch/hppc/Containers.java create mode 100755 src/main/java/com/carrotsearch/hppc/DoubleArrayDeque.java create mode 100755 src/main/java/com/carrotsearch/hppc/DoubleArrayList.java create mode 100755 src/main/java/com/carrotsearch/hppc/DoubleBufferVisualizer.java create mode 100755 src/main/java/com/carrotsearch/hppc/DoubleCollection.java create mode 100755 src/main/java/com/carrotsearch/hppc/DoubleContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/DoubleDeque.java create mode 100755 src/main/java/com/carrotsearch/hppc/DoubleIndexedContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/DoubleLookupContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/DoublePgmIndex.java create mode 100755 src/main/java/com/carrotsearch/hppc/DoubleStack.java create mode 100755 src/main/java/com/carrotsearch/hppc/FloatArrayDeque.java create mode 100755 src/main/java/com/carrotsearch/hppc/FloatArrayList.java create mode 100755 src/main/java/com/carrotsearch/hppc/FloatBufferVisualizer.java create mode 100755 src/main/java/com/carrotsearch/hppc/FloatCollection.java create mode 100755 src/main/java/com/carrotsearch/hppc/FloatContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/FloatDeque.java create mode 100755 src/main/java/com/carrotsearch/hppc/FloatIndexedContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/FloatLookupContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/FloatPgmIndex.java create mode 100755 src/main/java/com/carrotsearch/hppc/FloatStack.java create mode 100755 src/main/java/com/carrotsearch/hppc/Generated.java create mode 100755 src/main/java/com/carrotsearch/hppc/HashContainers.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntArrayDeque.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntArrayList.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntBufferVisualizer.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntByteAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntByteHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntByteMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntCharAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntCharHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntCharMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntCollection.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntDeque.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntDoubleAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntDoubleHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntDoubleMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntFloatAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntFloatHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntFloatMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntHashSet.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntIndexedContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntIntAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntIntHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntIntMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntLongAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntLongHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntLongMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntLookupContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntObjectAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntObjectHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntObjectMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntPgmIndex.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntSet.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntShortAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntShortHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntShortMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/IntStack.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongArrayDeque.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongArrayList.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongBufferVisualizer.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongByteAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongByteHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongByteMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongCharAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongCharHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongCharMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongCollection.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongDeque.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongDoubleAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongDoubleHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongDoubleMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongFloatAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongFloatHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongFloatMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongHashSet.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongIndexedContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongIntAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongIntHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongIntMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongLongAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongLongHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongLongMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongLookupContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongObjectAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongObjectHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongObjectMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongPgmIndex.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongSet.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongShortAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongShortHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongShortMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/LongStack.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectArrayDeque.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectArrayList.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectBufferVisualizer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectByteAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectByteHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectByteIdentityHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectByteMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectCharAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectCharHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectCharIdentityHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectCharMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectCollection.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectDeque.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectDoubleAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectDoubleHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectDoubleIdentityHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectDoubleMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectFloatAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectFloatHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectFloatIdentityHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectFloatMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectHashSet.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectIdentityHashSet.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectIndexedContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectIntAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectIntHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectIntIdentityHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectIntMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectLongAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectLongHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectLongIdentityHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectLongMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectLookupContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectObjectAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectObjectHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectObjectIdentityHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectObjectMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectSet.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectShortAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectShortHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectShortIdentityHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectShortMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ObjectStack.java create mode 100755 src/main/java/com/carrotsearch/hppc/PgmIndexUtil.java create mode 100755 src/main/java/com/carrotsearch/hppc/PlaModel.java create mode 100755 src/main/java/com/carrotsearch/hppc/Preallocable.java create mode 100755 src/main/java/com/carrotsearch/hppc/RamUsageEstimator.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortArrayDeque.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortArrayList.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortBufferVisualizer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortByteAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortByteHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortByteMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortCharAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortCharHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortCharMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortCollection.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortDeque.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortDoubleAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortDoubleHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortDoubleMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortFloatAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortFloatHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortFloatMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortHashSet.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortIndexedContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortIntAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortIntHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortIntMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortLongAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortLongHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortLongMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortLookupContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortObjectAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortObjectHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortObjectMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortSet.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortShortAssociativeContainer.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortShortHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortShortMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/ShortStack.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationCharByteHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationCharCharHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationCharDoubleHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationCharFloatHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationCharIntHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationCharLongHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationCharObjectHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationCharShortHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationIntByteHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationIntCharHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationIntDoubleHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationIntFloatHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationIntIntHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationIntLongHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationIntObjectHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationIntShortHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationLongByteHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationLongCharHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationLongDoubleHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationLongFloatHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationLongIntHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationLongLongHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationLongObjectHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationLongShortHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationObjectByteHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationObjectCharHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationObjectDoubleHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationObjectFloatHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationObjectIntHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationObjectLongHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationObjectObjectHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationObjectShortHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationShortByteHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationShortCharHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationShortDoubleHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationShortFloatHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationShortIntHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationShortLongHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationShortObjectHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/SortedIterationShortShortHashMap.java create mode 100755 src/main/java/com/carrotsearch/hppc/XorShift128P.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ByteByteComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ByteCharComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ByteComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ByteDoubleComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ByteFloatComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ByteIntComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ByteLongComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ByteObjectComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ByteShortComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/CharByteComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/CharCharComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/CharComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/CharDoubleComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/CharFloatComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/CharIntComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/CharLongComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/CharObjectComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/CharShortComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/DoubleByteComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/DoubleCharComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/DoubleComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/DoubleDoubleComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/DoubleFloatComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/DoubleIntComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/DoubleLongComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/DoubleObjectComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/DoubleShortComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/FloatByteComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/FloatCharComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/FloatComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/FloatDoubleComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/FloatFloatComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/FloatIntComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/FloatLongComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/FloatObjectComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/FloatShortComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/IntByteComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/IntCharComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/IntComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/IntDoubleComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/IntFloatComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/IntIntComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/IntLongComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/IntObjectComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/IntShortComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/LongByteComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/LongCharComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/LongComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/LongDoubleComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/LongFloatComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/LongIntComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/LongLongComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/LongObjectComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/LongShortComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ObjectByteComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ObjectCharComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ObjectDoubleComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ObjectFloatComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ObjectIntComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ObjectLongComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ObjectObjectComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ObjectShortComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ShortByteComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ShortCharComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ShortComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ShortDoubleComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ShortFloatComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ShortIntComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ShortLongComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ShortObjectComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/comparators/ShortShortComparator.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ByteCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/CharByteCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/CharCharCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/CharCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/CharDoubleCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/CharFloatCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/CharIntCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/CharLongCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/CharObjectCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/CharShortCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/DoubleCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/FloatCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/IntByteCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/IntCharCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/IntCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/IntDoubleCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/IntFloatCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/IntIntCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/IntLongCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/IntObjectCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/IntShortCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/LongByteCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/LongCharCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/LongCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/LongDoubleCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/LongFloatCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/LongIntCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/LongLongCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/LongObjectCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/LongShortCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ObjectByteCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ObjectCharCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ObjectCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ObjectDoubleCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ObjectFloatCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ObjectIntCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ObjectLongCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ObjectObjectCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ObjectShortCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ShortByteCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ShortCharCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ShortCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ShortDoubleCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ShortFloatCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ShortIntCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ShortLongCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ShortObjectCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/cursors/ShortShortCursor.java create mode 100755 src/main/java/com/carrotsearch/hppc/internals/SuppressForbidden.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ByteBytePredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ByteCharPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ByteDoublePredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ByteFloatPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ByteIntPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ByteLongPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ByteObjectPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/BytePredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ByteShortPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/CharBytePredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/CharCharPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/CharDoublePredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/CharFloatPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/CharIntPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/CharLongPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/CharObjectPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/CharPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/CharShortPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/DoubleBytePredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/DoubleCharPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/DoubleDoublePredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/DoubleFloatPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/DoubleIntPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/DoubleLongPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/DoubleObjectPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/DoublePredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/DoubleShortPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/FloatBytePredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/FloatCharPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/FloatDoublePredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/FloatFloatPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/FloatIntPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/FloatLongPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/FloatObjectPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/FloatPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/FloatShortPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/IntBytePredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/IntCharPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/IntDoublePredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/IntFloatPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/IntIntPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/IntLongPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/IntObjectPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/IntPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/IntShortPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/LongBytePredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/LongCharPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/LongDoublePredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/LongFloatPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/LongIntPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/LongLongPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/LongObjectPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/LongPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/LongShortPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ObjectBytePredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ObjectCharPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ObjectDoublePredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ObjectFloatPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ObjectIntPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ObjectLongPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ObjectObjectPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ObjectPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ObjectShortPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ShortBytePredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ShortCharPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ShortDoublePredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ShortFloatPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ShortIntPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ShortLongPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ShortObjectPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ShortPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/predicates/ShortShortPredicate.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ByteByteProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ByteCharProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ByteDoubleProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ByteFloatProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ByteIntProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ByteLongProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ByteObjectProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ByteProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ByteShortProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/CharByteProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/CharCharProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/CharDoubleProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/CharFloatProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/CharIntProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/CharLongProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/CharObjectProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/CharProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/CharShortProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/DoubleByteProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/DoubleCharProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/DoubleDoubleProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/DoubleFloatProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/DoubleIntProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/DoubleLongProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/DoubleObjectProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/DoubleProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/DoubleShortProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/FloatByteProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/FloatCharProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/FloatDoubleProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/FloatFloatProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/FloatIntProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/FloatLongProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/FloatObjectProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/FloatProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/FloatShortProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/IntByteProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/IntCharProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/IntDoubleProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/IntFloatProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/IntIntProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/IntLongProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/IntObjectProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/IntProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/IntShortProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/LongByteProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/LongCharProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/LongDoubleProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/LongFloatProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/LongIntProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/LongLongProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/LongObjectProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/LongProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/LongShortProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ObjectByteProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ObjectCharProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ObjectDoubleProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ObjectFloatProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ObjectIntProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ObjectLongProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ObjectObjectProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ObjectProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ObjectShortProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ShortByteProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ShortCharProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ShortDoubleProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ShortFloatProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ShortIntProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ShortLongProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ShortObjectProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ShortProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/procedures/ShortShortProcedure.java create mode 100755 src/main/java/com/carrotsearch/hppc/sorting/IndirectSort.java create mode 100755 src/main/java/com/carrotsearch/hppc/sorting/QuickSort.java create mode 100755 src/main/java/jdk_internal/bidi/Annotation.java create mode 100755 src/main/java/jdk_internal/bidi/AttributedCharacterIterator.java create mode 100755 src/main/java/jdk_internal/bidi/AttributedString.java create mode 100755 src/main/java/jdk_internal/bidi/Bidi.java create mode 100755 src/main/java/jdk_internal/bidi/CharacterIterator.java create mode 100755 src/main/java/jdk_internal/bidi/Normalizer.java create mode 100755 src/main/java/jdk_internal/bidi/NumericShaper.java create mode 100755 src/main/java/jdk_internal/bidi/ParseException.java create mode 100755 src/main/java/jdk_internal/bidi/SunNormalizer.java create mode 100755 src/main/java/jdk_internal/bidi/TextAttribute.java create mode 100755 src/main/java/jdk_internal/bidi/icu/impl/BMPSet.java create mode 100755 src/main/java/jdk_internal/bidi/icu/impl/CharTrie.java create mode 100755 src/main/java/jdk_internal/bidi/icu/impl/CharacterIteratorWrapper.java create mode 100755 src/main/java/jdk_internal/bidi/icu/impl/ICUBinary.java create mode 100755 src/main/java/jdk_internal/bidi/icu/impl/Norm2AllModes.java create mode 100755 src/main/java/jdk_internal/bidi/icu/impl/NormalizerImpl.java create mode 100755 src/main/java/jdk_internal/bidi/icu/impl/Punycode.java create mode 100755 src/main/java/jdk_internal/bidi/icu/impl/ReplaceableUCharacterIterator.java create mode 100755 src/main/java/jdk_internal/bidi/icu/impl/StringPrepDataReader.java create mode 100755 src/main/java/jdk_internal/bidi/icu/impl/Trie.java create mode 100755 src/main/java/jdk_internal/bidi/icu/impl/Trie2.java create mode 100755 src/main/java/jdk_internal/bidi/icu/impl/Trie2_16.java create mode 100755 src/main/java/jdk_internal/bidi/icu/impl/UBiDiProps.java create mode 100755 src/main/java/jdk_internal/bidi/icu/impl/UCharacterProperty.java create mode 100755 src/main/java/jdk_internal/bidi/icu/impl/UnicodeSetStringSpan.java create mode 100755 src/main/java/jdk_internal/bidi/icu/impl/Utility.java create mode 100755 src/main/java/jdk_internal/bidi/icu/lang/UCharacter.java create mode 100755 src/main/java/jdk_internal/bidi/icu/lang/UCharacterDirection.java create mode 100755 src/main/java/jdk_internal/bidi/icu/lang/UCharacterEnums.java create mode 100755 src/main/java/jdk_internal/bidi/icu/text/BidiBase.java create mode 100755 src/main/java/jdk_internal/bidi/icu/text/BidiLine.java create mode 100755 src/main/java/jdk_internal/bidi/icu/text/BidiRun.java create mode 100755 src/main/java/jdk_internal/bidi/icu/text/BidiWriter.java create mode 100755 src/main/java/jdk_internal/bidi/icu/text/FilteredNormalizer2.java create mode 100755 src/main/java/jdk_internal/bidi/icu/text/Normalizer2.java create mode 100755 src/main/java/jdk_internal/bidi/icu/text/NormalizerBase.java create mode 100755 src/main/java/jdk_internal/bidi/icu/text/Replaceable.java create mode 100755 src/main/java/jdk_internal/bidi/icu/text/ReplaceableString.java create mode 100755 src/main/java/jdk_internal/bidi/icu/text/StringPrep.java create mode 100755 src/main/java/jdk_internal/bidi/icu/text/UCharacterIterator.java create mode 100755 src/main/java/jdk_internal/bidi/icu/text/UTF16.java create mode 100755 src/main/java/jdk_internal/bidi/icu/text/UnicodeSet.java create mode 100755 src/main/java/jdk_internal/bidi/icu/util/CodePointMap.java create mode 100755 src/main/java/jdk_internal/bidi/icu/util/CodePointTrie.java create mode 100755 src/main/java/jdk_internal/bidi/icu/util/OutputInt.java create mode 100755 src/main/java/jdk_internal/bidi/icu/util/VersionInfo.java create mode 100755 src/main/java/net/lax1dude/eaglercraft/v1_8/EaglerBidiReorder.java create mode 100755 src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderRealisticWaterNormalsMix.java create mode 100755 src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderMissingException.java create mode 100755 src/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/GenLayerEaglerRivers.java diff --git a/desktopRuntime/resources/EPKVersionIdentifier.txt b/desktopRuntime/resources/EPKVersionIdentifier.txt index 50356da8..503c4b5b 100755 --- a/desktopRuntime/resources/EPKVersionIdentifier.txt +++ b/desktopRuntime/resources/EPKVersionIdentifier.txt @@ -1 +1 @@ -u46 \ No newline at end of file +u47 \ No newline at end of file diff --git a/desktopRuntime/resources/assets/eagler/CREDITS.txt b/desktopRuntime/resources/assets/eagler/CREDITS.txt index 1885e21e..654d455d 100755 --- a/desktopRuntime/resources/assets/eagler/CREDITS.txt +++ b/desktopRuntime/resources/assets/eagler/CREDITS.txt @@ -217,6 +217,28 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + Project Name: High Performance Primitive Collections + Project Author: Carrot Search + Project URL: http://labs.carrotsearch.com/hppc.html + + Used For: Primitive collections library for the client + + * Copyright 2010-2013, Carrot Search s.c., Boznicza 11/56, Poznan, Poland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + Project Name: Google Guava Project Author: Google Project URL: https://github.com/google/guava @@ -514,6 +536,45 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + Project Name: OpenJDK + Project Author: Oracle, IBM + Project URL: https://openjdk.org/projects/jdk/17/ + + Used For: Debloated version of IBM's ICU4J for reordering Arabic and Hebrew text + + * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + + * (C) Copyright IBM Corp. 1999-2003 - All Rights Reserved + * + * The original version of this source code and documentation is + * copyrighted and owned by IBM. These materials are provided + * under terms of a License Agreement between IBM and Sun. + * This technology is protected by multiple US and International + * patents. This notice and attribution to IBM may not be removed. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + Project Name: Java-WebSocket Project Author: Nathan Rajlich (TooTallNate) Project URL: http://tootallnate.github.io/Java-WebSocket diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/accel_particle_forward.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/accel_particle_forward.fsh index c55d8fef..554b324e 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/accel_particle_forward.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/accel_particle_forward.fsh @@ -206,6 +206,7 @@ void main() { vec3 dlightDist3f, dlightDir3f, dlightColor3f; int safeLightCount = u_dynamicLightCount1i > 12 ? 0 : u_dynamicLightCount1i; // hate this + float cm; for(int i = 0; i < safeLightCount; ++i) { dlightDist3f = worldPosition4f.xyz - u_dynamicLightArray[i].u_lightPosition4f.xyz; dlightDir3f = normalize(dlightDist3f); @@ -215,9 +216,11 @@ void main() { continue; } dlightColor3f = u_dynamicLightArray[i].u_lightColor4f.rgb / dot(dlightDist3f, dlightDist3f); - if(dlightColor3f.r + dlightColor3f.g + dlightColor3f.b < 0.025) { + cm = dlightColor3f.r + dlightColor3f.g + dlightColor3f.b; + if(cm < 0.025) { continue; } + dlightColor3f *= ((cm - 0.025) / cm); lightColor3f += eaglercraftLighting(diffuseColor4f.rgb, dlightColor3f, -worldDirection4f.xyz, dlightDir3f, normalVector3f, materialData3f, metalN, metalK) * u_blockSkySunDynamicLightFac4f.w; } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/deferred_combine.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/deferred_combine.fsh index 4fbbc84f..c5155b2b 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/deferred_combine.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/deferred_combine.fsh @@ -68,7 +68,7 @@ void main() { vec4 materialData4f; float depth = textureLod(u_gbufferDepthTexture, v_position2f, 0.0).r; - if(depth < 0.00001) { + if(depth == 0.0) { discard; } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/deferred_fog.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/deferred_fog.fsh index f544f13c..19de1c08 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/deferred_fog.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/deferred_fog.fsh @@ -52,7 +52,7 @@ void main() { vec4 fragPos4f = vec4(v_position2f, textureLod(u_fogDepthTexture, v_position2f, 0.0).r, 1.0); #ifdef COMPILE_FOG_ATMOSPHERE - if(fragPos4f.z <= 0.0000001) { + if(fragPos4f.z == 0.0) { discard; } #endif diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/forward_core.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/forward_core.fsh index c7549099..3ba9fcf5 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/forward_core.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/forward_core.fsh @@ -404,6 +404,7 @@ void main() { vec3 dlightDist3f, dlightDir3f, dlightColor3f; int safeLightCount = u_dynamicLightCount1i > 12 ? 0 : u_dynamicLightCount1i; // hate this + float cm; for(int i = 0; i < safeLightCount; ++i) { dlightDist3f = worldPosition4f.xyz - u_dynamicLightArray[i].u_lightPosition4f.xyz; dlightDir3f = normalize(dlightDist3f); @@ -412,9 +413,11 @@ void main() { continue; } dlightColor3f = u_dynamicLightArray[i].u_lightColor4f.rgb / dot(dlightDist3f, dlightDist3f); - if(dlightColor3f.r + dlightColor3f.g + dlightColor3f.b < 0.025) { + cm = dlightColor3f.r + dlightColor3f.g + dlightColor3f.b; + if(cm < 0.025) { continue; } + dlightColor3f *= ((cm - 0.025) / cm); lightColor3f += eaglercraftLighting(diffuseColor4f.rgb, dlightColor3f, -worldDirection4f.xyz, dlightDir3f, normalVector3f, materialData3f, metalN, metalK) * u_blockSkySunDynamicLightFac4f.w; } @@ -451,7 +454,7 @@ void main() { #ifdef COMPILE_FOG_LIGHT_SHAFTS fogBlend4f.rgb *= pow(textureLod(u_lightShaftsTexture, v_positionClip2f * 0.5 + 0.5, 0.0).r * 0.9 + 0.1, 2.25); - fogBlend4f.a = fogBlend4f.a * 0.9 + 0.1; + fogBlend4f.a = fogBlend4f.a * 0.85 + 0.2; #endif break; } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/forward_glass_highlights.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/forward_glass_highlights.fsh index 7cab95f9..4409765c 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/forward_glass_highlights.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/forward_glass_highlights.fsh @@ -268,6 +268,7 @@ void main() { vec3 dlightDist3f, dlightDir3f, dlightColor3f; int safeLightCount = u_dynamicLightCount1i > 12 ? 0 : u_dynamicLightCount1i; // hate this + float cm; for(int i = 0; i < safeLightCount; ++i) { dlightDist3f = u_dynamicLightArray[i].u_lightPosition4f.xyz - worldPosition4f.xyz; dlightDir3f = normalize(dlightDist3f); @@ -275,9 +276,11 @@ void main() { continue; } dlightColor3f = u_dynamicLightArray[i].u_lightColor4f.rgb / dot(dlightDist3f, dlightDist3f); - if(dlightColor3f.r + dlightColor3f.g + dlightColor3f.b < 0.025) { + cm = dlightColor3f.r + dlightColor3f.g + dlightColor3f.b; + if(cm < 0.025) { continue; } + dlightColor3f *= ((cm - 0.025) / cm); lightColor3f += eaglercraftLighting_Glass(dlightColor3f, -worldDirection4f.xyz, dlightDir3f, normalVector3f) * u_blockSkySunDynamicLightFac4f.w; } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/hand_depth_mask.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/hand_depth_mask.fsh index 13d15369..8771c3dd 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/hand_depth_mask.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/hand_depth_mask.fsh @@ -25,5 +25,5 @@ in vec2 v_position2f; uniform sampler2D u_depthTexture; void main() { - gl_FragDepth = textureLod(u_depthTexture, v_position2f, 0.0).r <= 0.0000001 ? 0.0 : 1.0; + gl_FragDepth = textureLod(u_depthTexture, v_position2f, 0.0).r == 0.0 ? 0.0 : 1.0; } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/light_shafts_sample.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/light_shafts_sample.fsh index e0d71711..41ba1cfc 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/light_shafts_sample.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/light_shafts_sample.fsh @@ -84,7 +84,7 @@ float shadow(in vec3 coords) { void main() { output1f = 0.0; float depth = textureLod(u_gbufferDepthTexture, v_position2f, 0.0).r; - if(depth < 0.00001) { + if(depth == 0.0) { return; } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/lighting_point.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/lighting_point.fsh index 1fcbd0ae..11a00ec1 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/lighting_point.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/lighting_point.fsh @@ -47,7 +47,7 @@ void main() { vec3 materialData3f; float depth = textureLod(u_gbufferDepthTexture, v_position2f, 0.0).r; - if(depth < 0.00001) { + if(depth == 0.0) { discard; } @@ -59,11 +59,14 @@ void main() { worldSpacePosition = u_inverseViewMatrix4f * worldSpacePosition; vec3 lightDist = (worldSpacePosition.xyz / worldSpacePosition.w) - u_lightPosition3f; vec3 color3f = u_lightColor3f / dot(lightDist, lightDist); + float cm = color3f.r + color3f.g + color3f.b; - if(color3f.r + color3f.g + color3f.b < 0.025) { + if(cm < 0.025) { discard; } + color3f *= ((cm - 0.025) / cm); + vec4 sampleVar4f = textureLod(u_gbufferColorTexture, v_position2f, 0.0); diffuseColor3f.rgb = sampleVar4f.rgb; lightmapCoords2f.x = sampleVar4f.a; diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/lighting_sun.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/lighting_sun.fsh index 0659f27c..cc1e1201 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/lighting_sun.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/lighting_sun.fsh @@ -64,6 +64,14 @@ void main() { #endif #endif + float depth = textureLod(u_gbufferDepthTexture, v_position2f, 0.0).r; + +#ifndef COMPILE_SUN_SHADOW + if(depth == 0.0) { + discard; + } +#endif + vec4 sampleVar4f = textureLod(u_gbufferNormalTexture, v_position2f, 0.0); #ifndef COMPILE_SUN_SHADOW @@ -77,14 +85,6 @@ void main() { normalVector3f.xyz = sampleVar4f.rgb * 2.0 - 1.0; lightmapCoords2f.y = sampleVar4f.a; - float depth = textureLod(u_gbufferDepthTexture, v_position2f, 0.0).r; - -#ifndef COMPILE_SUN_SHADOW - if(depth < 0.00001) { - discard; - } -#endif - sampleVar4f = textureLod(u_gbufferColorTexture, v_position2f, 0.0); diffuseColor3f.rgb = sampleVar4f.rgb; lightmapCoords2f.x = sampleVar4f.a; diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/post_bloom_bright.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/post_bloom_bright.fsh index 685586f0..69d2416b 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/post_bloom_bright.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/post_bloom_bright.fsh @@ -39,7 +39,7 @@ void main() { if(inputColor.a > 0.0) { emission = textureLod(u_gbufferMaterialTexture, alignedUV, 0.0).b; }else { - emission = textureLod(u_gbufferDepthTexture, alignedUV, 0.0).r <= 0.0000001 ? 10.0 : 0.0; + emission = textureLod(u_gbufferDepthTexture, alignedUV, 0.0).r == 0.0 ? 10.0 : 0.0; } float f = dot(inputColor.rgb, vec3(0.2126, 0.7152, 0.0722)) * (5.0 + emission * 15.0); if(f > 2.0 + exposure) { diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/post_tonemap.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/post_tonemap.fsh index 3064179e..4e6b3d3f 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/post_tonemap.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/post_tonemap.fsh @@ -34,7 +34,7 @@ void main() { float lumaHDR = textureLod(u_framebufferLumaAvgInput, vec2(0.5), 0.0).r; vec3 input3f = textureLod(u_lightingHDRFramebufferTexture, v_position2f, 0.0).rgb; - input3f /= (0.07 + clamp(lumaHDR * 6.0, 0.2, 4.0)); + input3f /= (0.07 + clamp(lumaHDR * 5.0, 0.18, 4.0)); input3f *= u_exposure3f; diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_mask.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_mask.fsh index 58724b36..dcef9f47 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_mask.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_mask.fsh @@ -29,9 +29,15 @@ uniform vec2 u_textureCoords02; #endif void main() { -#ifdef COMPILE_NORMAL_ATTRIB - output4f = vec4(v_normal3f * 0.5 + 0.5, 1.0); +#ifdef COMPILE_LIGHTMAP_ATTRIB + float skyLight = v_lightmap2f.y; #else - output4f = vec4(0.0, 1.0, 0.0, 1.0); + float skyLight = u_textureCoords02.y; +#endif + skyLight = 0.004 + skyLight * 0.996; +#ifdef COMPILE_NORMAL_ATTRIB + output4f = vec4(v_normal3f * 0.5 + 0.5, skyLight); +#else + output4f = vec4(0.0, 1.0, 0.0, skyLight); #endif } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_noise.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_noise.fsh index ce164e02..013820cf 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_noise.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_noise.fsh @@ -1,7 +1,7 @@ #line 2 /* - * Copyright (c) 2023 lax1dude. All Rights Reserved. + * Copyright (c) 2023-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -37,5 +37,5 @@ void main() { sampleC = textureLod(u_noiseTexture, fract(sampleC) * 0.46875 + vec2(0.515625, 0.515625), 0.0).rg; vec2 sampleD = v_position2f + vec2(-0.135, 0.092) * u_waveTimer4f.x + sampleC * 0.1; sampleD = textureLod(u_noiseTexture, fract(sampleD) * 0.46875 + vec2(0.015625, 0.515625), 0.0).rg; - realisticWaterDisplacementOutput1f = dot(vec4(sampleA.r, sampleB.r, sampleC.r, sampleD.r), vec4(0.63, 0.40, 0.035, 0.035)) + dot(vec2(sampleC.g, sampleD.g), vec2(-0.075 * sampleA.g, 0.053 * sampleA.r)); + realisticWaterDisplacementOutput1f = exp((dot(vec4(sampleA.r, sampleB.r, sampleC.r, sampleD.r), vec4(0.63, 0.40, 0.035, 0.035)) + dot(vec2(sampleC.g, sampleD.g), vec2(-0.075 * sampleA.g, 0.053 * sampleA.r))) * 2.0); } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_normals.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_normals.fsh index 7140a7a1..720e2fa8 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_normals.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_normals.fsh @@ -1,7 +1,7 @@ #line 2 /* - * Copyright (c) 2023 lax1dude. All Rights Reserved. + * Copyright (c) 2023-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -31,5 +31,5 @@ void main() { float A = textureLod(u_displacementTexture, v_position2f, 0.0).r; float B = textureLod(u_displacementTexture, v_position2f + vec2(u_sampleOffset2f.x, 0.0), 0.0).r; float C = textureLod(u_displacementTexture, v_position2f - vec2(0.0, u_sampleOffset2f.y), 0.0).r; - realisticWaterNormalOutput2f = clamp((vec2(A * A) - vec2(B, C) * vec2(B, C)) * 10.0 + 0.5, vec2(0.0), vec2(1.0)); + realisticWaterNormalOutput2f = clamp((vec2(A * A) - vec2(B, C) * vec2(B, C)) * 0.5 + 0.5, vec2(0.0), vec2(1.0)); } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_normals_mix.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_normals_mix.fsh new file mode 100755 index 00000000..e9646ccf --- /dev/null +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_normals_mix.fsh @@ -0,0 +1,35 @@ +#line 2 + +/* + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +precision lowp int; +precision mediump float; +precision mediump sampler2D; + +in vec2 v_position2f; + +layout(location = 0) out vec4 combinedNormalsOutput4f; + +uniform sampler2D u_gbufferNormalsTexture; +uniform sampler2D u_surfaceNormalsTexture; + +void main() { + combinedNormalsOutput4f = textureLod(u_surfaceNormalsTexture, v_position2f, 0.0); + if(combinedNormalsOutput4f.a > 0.0) return; + combinedNormalsOutput4f.rgb = textureLod(u_gbufferNormalsTexture, v_position2f, 0.0).rgb; + combinedNormalsOutput4f.a = 0.0; +} diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_render.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_render.fsh index 900d6868..c39f835b 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_render.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_render.fsh @@ -1,7 +1,7 @@ #line 2 /* - * Copyright (c) 2023 lax1dude. All Rights Reserved. + * Copyright (c) 2023-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -230,16 +230,17 @@ void main() { worldPosition4fOff.xyz += u_wavingBlockOffset3f; vec2 rotatedUV2f = worldPosition4fOff.xz + (block1f == 10.0 ? u_waterWindOffset4f.z * texCoords2f : u_waterWindOffset4f.xy); - rotatedUV2f *= (block1f == 10.0 ? 0.75 : 0.25); + rotatedUV2f *= (block1f == 10.0 ? 0.30 : 0.10); mat3 cf = cotangent_frame(normalVector3f, worldDirection4f.xyz, rotatedUV2f); - vec3 surfaceNormalsMap3f = vec3(textureLod(u_normalMap, rotatedUV2f, 0.0).rg, 0.0); - surfaceNormalsMap3f.xy *= 2.0; - surfaceNormalsMap3f.xy -= 1.0; + vec3 surfaceNormalsMap3f = vec3(textureLod(u_normalMap, rotatedUV2f * 0.68, 0.0).rg - 0.5, 0.0); + surfaceNormalsMap3f.xy += textureLod(u_normalMap, rotatedUV2f, 0.0).rg - 0.5; + surfaceNormalsMap3f.xy += textureLod(u_normalMap, rotatedUV2f * 2.33, 0.0).rg - 0.5; + surfaceNormalsMap3f.xy *= (2.0 / 3.0); vec3 surfaceNormalsMapFlat3f = cf * surfaceNormalsMap3f; - surfaceNormalsMapFlat3f *= 0.1; + surfaceNormalsMapFlat3f *= 0.15; - surfaceNormalsMap3f.z = 8.0; + surfaceNormalsMap3f.z = 7.0; surfaceNormalsMap3f = normalize(surfaceNormalsMap3f); normalVector3f = surfaceNormalsMap3f = cf * surfaceNormalsMap3f; @@ -268,6 +269,18 @@ void main() { vec4 envMapSample4f = textureLod(u_reflectionMap, reflectCoordsR.xy, 0.0); vec4 refractionSample = textureLod(u_refractionMap, reflectCoordsL.xy, 0.0); + if(refractionSample.a == 0.0) { + reflectCoordsL = mat4x3( + u_modelViewProjMat4f_[0].xyw, + u_modelViewProjMat4f_[1].xyw, + u_modelViewProjMat4f_[2].xyw, + u_modelViewProjMat4f_[3].xyw) * worldPosition4f; + reflectCoordsL.xy /= reflectCoordsL.z; + reflectCoordsL.xy *= 0.5; + reflectCoordsL.xy += 0.5; + refractionSample = textureLod(u_refractionMap, reflectCoordsL.xy, 0.0); + } + #ifdef COMPILE_COLOR_ATTRIB refractionSample *= v_color4f * v_color4f * u_color4f * u_color4f; #else @@ -374,6 +387,7 @@ void main() { vec3 dlightDist3f, dlightDir3f, dlightColor3f; int safeLightCount = u_dynamicLightCount1i > 12 ? 0 : u_dynamicLightCount1i; // hate this + float cm; for(int i = 0; i < safeLightCount; ++i) { dlightDist3f = u_dynamicLightArray[i].u_lightPosition4f.xyz - worldPosition4f.xyz; dlightDir3f = normalize(dlightDist3f); @@ -381,9 +395,11 @@ void main() { continue; } dlightColor3f = u_dynamicLightArray[i].u_lightColor4f.rgb / dot(dlightDist3f, dlightDist3f); - if(dlightColor3f.r + dlightColor3f.g + dlightColor3f.b < 0.025) { + cm = dlightColor3f.r + dlightColor3f.g + dlightColor3f.b; + if(cm < 0.025) { continue; } + dlightColor3f *= ((cm - 0.025) / cm); lightColor3f += eaglercraftLighting_Water(diffuseColor4f.rgb, dlightColor3f, -worldDirection4f.xyz, dlightDir3f, normalVector3f) * u_blockSkySunDynamicLightFac4f.w; } @@ -419,7 +435,7 @@ void main() { #ifdef COMPILE_FOG_LIGHT_SHAFTS fogBlend4f.rgb *= pow(textureLod(u_lightShaftsTexture, v_positionClip2f * 0.5 + 0.5, 0.0).r * 0.9 + 0.1, 2.25); - fogBlend4f.a = fogBlend4f.a * 0.9 + 0.1; + fogBlend4f.a = fogBlend4f.a * 0.85 + 0.2; #endif break; } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/reproject_ssr.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/reproject_ssr.fsh index 30f9d965..9efb9c5d 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/reproject_ssr.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/reproject_ssr.fsh @@ -1,7 +1,7 @@ #line 2 /* - * Copyright (c) 2023 lax1dude. All Rights Reserved. + * Copyright (c) 2023-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -41,72 +41,96 @@ uniform float u_sampleStep1f; uniform vec4 u_pixelAlignment4f; +uniform int u_sampleDelta1i; + #define maxAge 55.0 #define maxSamples 50.0 void main() { vec2 v_position2f2 = (floor(v_position2f * u_pixelAlignment4f.xy) + 0.25) * (2.0 / u_pixelAlignment4f.zw); - reflectionOutput4f = vec4(0.0, 0.0, 0.0, 0.0); - hitVectorOutput4f = vec4(0.0, 0.0, 0.0, 0.0); float fragDepth = textureLod(u_gbufferDepthTexture, v_position2f2, 0.0).r; if(fragDepth < 0.000001) { + reflectionOutput4f = vec4(0.0, 0.0, 0.0, 0.0); + hitVectorOutput4f = vec4(0.0, 0.0, 0.0, 0.0); return; } - vec4 reflectionInput4f = textureLod(u_reprojectionReflectionInput4f, v_position2f, 0.0); - vec4 hitVectorInput4f = textureLod(u_reprojectionHitVectorInput4f, v_position2f, 0.0); - hitVectorInput4f.a += 1.0; - float f = reflectionInput4f.a < 1.0 ? 1.0 : reflectionInput4f.a; - reflectionInput4f.a = hitVectorInput4f.a > maxAge ? f : reflectionInput4f.a; - if(reflectionInput4f.a < 1.0) { - reflectionOutput4f = reflectionInput4f; - hitVectorOutput4f = hitVectorInput4f; - return; + vec4 reflectionBuffer4f = textureLod(u_reprojectionReflectionInput4f, v_position2f, 0.0); + vec4 hitVectorBuffer4f = textureLod(u_reprojectionHitVectorInput4f, v_position2f, 0.0); + vec4 surfaceNormal4f = textureLod(u_gbufferNormalTexture, v_position2f2, 0.0); + surfaceNormal4f.xyz *= 2.0; + surfaceNormal4f.xyz -= 1.0; + + vec4 reflectionInput4f; + vec4 hitVectorInput4f; + float f; + vec4 fragPos4f; + vec4 reflectionNormal4f; + float sampleStepMod; + vec3 sampleOffset3f; + vec3 reflectionSamplePos3f; + float reflectDepthSample; + vec2 sampleFragDepth; + vec4 colorSample; + + for(int itr = 0; itr < u_sampleDelta1i; ++itr) { + reflectionInput4f = reflectionBuffer4f; + hitVectorInput4f = hitVectorBuffer4f; + reflectionBuffer4f = vec4(0.0, 0.0, 0.0, 0.0); + hitVectorBuffer4f = vec4(0.0, 0.0, 0.0, 0.0); + hitVectorInput4f.a += 1.0; + f = reflectionInput4f.a < 1.0 ? 1.0 : reflectionInput4f.a; + reflectionInput4f.a = hitVectorInput4f.a > maxAge ? f : reflectionInput4f.a; + if(reflectionInput4f.a < 1.0) { + reflectionBuffer4f = reflectionInput4f; + hitVectorBuffer4f = hitVectorInput4f; + continue; + } + + fragPos4f = u_inverseProjectionMatrix4f * (vec4(v_position2f2, fragDepth, 1.0) * 2.0 - 1.0); + fragPos4f.xyz /= fragPos4f.w; + fragPos4f.w = 1.0; + reflectionNormal4f.xyz = reflect(normalize(fragPos4f.xyz), surfaceNormal4f.xyz); + reflectionNormal4f.w = 1.0; + sampleStepMod = (reflectionInput4f.a * 0.03 + 0.15 + length(fragPos4f.xyz) * 0.03) * u_sampleStep1f; + sampleOffset3f = reflectionNormal4f.xyz * reflectionInput4f.a * sampleStepMod; + fragPos4f.xyz += sampleOffset3f; + reflectionNormal4f = u_lastProjectionMatrix4f * fragPos4f; + reflectionNormal4f.xyz /= reflectionNormal4f.w; + reflectionNormal4f.w = 1.0; + reflectionSamplePos3f = reflectionNormal4f.xyz; + reflectionSamplePos3f *= 0.5; + reflectionSamplePos3f += 0.5; + reflectionSamplePos3f.xy = (floor(reflectionSamplePos3f.xy * u_pixelAlignment4f.zw) + 0.5) * (0.5 / u_pixelAlignment4f.xy); + + if(clamp(reflectionSamplePos3f.xy, vec2(0.001), vec2(0.999)) != reflectionSamplePos3f.xy) { + continue; + } + + reflectDepthSample = textureLod(u_lastFrameDepthInput, reflectionSamplePos3f.xy, 0.0).r; + sampleFragDepth = u_lastInverseProjMatrix4x2f * vec4(reflectionNormal4f.xy, reflectDepthSample * 2.0 - 1.0, 1.0); + sampleFragDepth.x /= sampleFragDepth.y; + + reflectDepthSample = sampleFragDepth.x - fragPos4f.z; + if(reflectDepthSample < sampleStepMod * 3.0) { + reflectionInput4f.a += 1.0; + reflectionBuffer4f = reflectionInput4f.a >= maxSamples ? vec4(0.0, 0.0, 0.0, 0.0) : reflectionInput4f; + hitVectorBuffer4f = vec4(0.0, 0.0, 0.0, hitVectorInput4f.a); + continue; + } + + if(abs(reflectDepthSample) > sampleStepMod * 6.0) { + continue; + } + + colorSample = textureLod(u_lastFrameColorInput4f, reflectionSamplePos3f.xy, 0.0); + reflectionBuffer4f = vec4(colorSample.rgb, 0.0); + reflectionBuffer4f.g += 0.0005; + hitVectorBuffer4f = vec4(colorSample.a > 0.0 ? sampleOffset3f : vec3(0.0), 0.0); + hitVectorBuffer4f.g += colorSample.a > 0.0 ? 0.0004 : 0.0; } - vec4 fragPos4f = u_inverseProjectionMatrix4f * (vec4(v_position2f2, fragDepth, 1.0) * 2.0 - 1.0); - fragPos4f.xyz /= fragPos4f.w; - fragPos4f.w = 1.0; - vec4 reflectionNormal4f = textureLod(u_gbufferNormalTexture, v_position2f2, 0.0); - reflectionNormal4f.xyz *= 2.0; - reflectionNormal4f.xyz -= 1.0; - reflectionNormal4f.xyz = reflect(normalize(fragPos4f.xyz), reflectionNormal4f.xyz); - reflectionNormal4f.w = 1.0; - float sampleStepMod = (reflectionInput4f.a * 0.03 + 0.15 + length(fragPos4f.xyz) * 0.03) * u_sampleStep1f; - vec3 sampleOffset3f = reflectionNormal4f.xyz * reflectionInput4f.a * sampleStepMod; - fragPos4f.xyz += sampleOffset3f; - reflectionNormal4f = u_lastProjectionMatrix4f * fragPos4f; - reflectionNormal4f.xyz /= reflectionNormal4f.w; - reflectionNormal4f.w = 1.0; - vec3 reflectionSamplePos3f = reflectionNormal4f.xyz; - reflectionSamplePos3f *= 0.5; - reflectionSamplePos3f += 0.5; - reflectionSamplePos3f.xy = (floor(reflectionSamplePos3f.xy * u_pixelAlignment4f.zw) + 0.5) * (0.5 / u_pixelAlignment4f.xy); - - if(clamp(reflectionSamplePos3f.xy, vec2(0.001), vec2(0.999)) != reflectionSamplePos3f.xy) { - return; - } - - float reflectDepthSample = textureLod(u_lastFrameDepthInput, reflectionSamplePos3f.xy, 0.0).r; - vec2 sampleFragDepth = u_lastInverseProjMatrix4x2f * vec4(reflectionNormal4f.xy, reflectDepthSample * 2.0 - 1.0, 1.0); - sampleFragDepth.x /= sampleFragDepth.y; - - reflectDepthSample = sampleFragDepth.x - fragPos4f.z; - if(reflectDepthSample < sampleStepMod * 3.0) { - reflectionInput4f.a += 1.0; - reflectionOutput4f = reflectionInput4f.a >= maxSamples ? vec4(0.0, 0.0, 0.0, 0.0) : reflectionInput4f; - hitVectorOutput4f = vec4(0.0, 0.0, 0.0, hitVectorInput4f.a); - return; - } - - if(abs(reflectDepthSample) > sampleStepMod * 6.0) { - return; - } - - vec4 colorSample = textureLod(u_lastFrameColorInput4f, reflectionSamplePos3f.xy, 0.0); - reflectionOutput4f = vec4(colorSample.rgb, 0.0); - reflectionOutput4f.g += 0.0005; - hitVectorOutput4f = vec4(colorSample.a > 0.0 ? sampleOffset3f : vec3(0.0), 0.0); - hitVectorOutput4f.g += colorSample.a > 0.0 ? 0.0004 : 0.0; + reflectionOutput4f = reflectionBuffer4f; + hitVectorOutput4f = hitVectorBuffer4f; } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/shader_pack_info.json b/desktopRuntime/resources/assets/eagler/glsl/deferred/shader_pack_info.json index 48660544..d60bfe2b 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/shader_pack_info.json +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/shader_pack_info.json @@ -1,7 +1,7 @@ { "name": "§eHigh Performance PBR", "desc": "Pack made from scratch specifically for this client, designed to give what I call the best balance between quality and performance possible in a browser but obviously that's just my opinion", - "vers": "1.2.2", + "vers": "1.3.0", "author": "lax1dude", "api_vers": 1, "features": [ diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/shadows_sun.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/shadows_sun.fsh index a11645ee..834fdba2 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/shadows_sun.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/shadows_sun.fsh @@ -79,7 +79,7 @@ void main() { output1f = 0.0; #endif float depth = textureLod(u_gbufferDepthTexture, v_position2f, 0.0).r; - if(depth < 0.00001) { + if(depth == 0.0) { return; } vec4 normalVector4f = textureLod(u_gbufferNormalTexture, v_position2f, 0.0); diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/ssao_generate.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/ssao_generate.fsh index 98b425ce..92a97bd7 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/ssao_generate.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/ssao_generate.fsh @@ -54,7 +54,7 @@ vec3(0.716,-0.439,0.543),vec3(-0.400,0.733,0.550)); void main() { vec3 originalClipSpacePos = vec3(v_position2f, textureLod(u_gbufferDepthTexture, v_position2f, 0.0).r); - if(originalClipSpacePos.z <= 0.0000001) { + if(originalClipSpacePos.z == 0.0) { output1f = 1.0; return; } diff --git a/desktopRuntime/resources/assets/eagler/icudt/nfc.nrm b/desktopRuntime/resources/assets/eagler/icudt/nfc.nrm new file mode 100755 index 0000000000000000000000000000000000000000..45c260858f9aea1031520e13b6087be76b6c9301 GIT binary patch literal 35136 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 literal 0 HcmV?d00001 diff --git a/desktopRuntime/resources/assets/eagler/icudt/nfkc.nrm b/desktopRuntime/resources/assets/eagler/icudt/nfkc.nrm new file mode 100755 index 0000000000000000000000000000000000000000..2c0587b6d455a6221287faf70600adcea6a7ef7b GIT binary patch literal 54144 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 Ky!El*-@gEZFs|AF literal 0 HcmV?d00001 diff --git a/desktopRuntime/resources/assets/eagler/icudt/ubidi.icu b/desktopRuntime/resources/assets/eagler/icudt/ubidi.icu new file mode 100755 index 0000000000000000000000000000000000000000..bec7b093064530bb5049258a4280cf55a113ec8a GIT binary patch literal 26640 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

ngp%RM_Lo+r~Rk8fO=eo^~3vttUsnd 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

dJi3^Hzt#8;9rpQiK=qd#XV+{X6B3-_A~y9C1wL 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�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%0Dd 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

yaCP82T-cxAOpW2q`cO(VGf3SLnH~Oc1 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 z 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%0AfGDTIWqyC# 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%0DlRUBwD+om^-rSnbY?b?uF%q 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Μ=r! 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 l6qhVQ2nv_bK?oiK03es}K?r05HYJxG5Bd< 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 E0E{*+IRF3v delta 234013 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.QGb2 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

%$p5V)l5kj=616! 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 diff --git a/src/game/java/net/minecraft/block/Block.java b/src/game/java/net/minecraft/block/Block.java index a5ea75cf..02b3ba96 100755 --- a/src/game/java/net/minecraft/block/Block.java +++ b/src/game/java/net/minecraft/block/Block.java @@ -40,7 +40,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockAir.java b/src/game/java/net/minecraft/block/BlockAir.java index e8cdb61d..e53a7158 100755 --- a/src/game/java/net/minecraft/block/BlockAir.java +++ b/src/game/java/net/minecraft/block/BlockAir.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockAnvil.java b/src/game/java/net/minecraft/block/BlockAnvil.java index 30d6bb33..fb42195a 100755 --- a/src/game/java/net/minecraft/block/BlockAnvil.java +++ b/src/game/java/net/minecraft/block/BlockAnvil.java @@ -32,7 +32,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockBanner.java b/src/game/java/net/minecraft/block/BlockBanner.java index e27bcb42..cbdda5d1 100755 --- a/src/game/java/net/minecraft/block/BlockBanner.java +++ b/src/game/java/net/minecraft/block/BlockBanner.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockBarrier.java b/src/game/java/net/minecraft/block/BlockBarrier.java index d61bc12c..abae54e4 100755 --- a/src/game/java/net/minecraft/block/BlockBarrier.java +++ b/src/game/java/net/minecraft/block/BlockBarrier.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockBasePressurePlate.java b/src/game/java/net/minecraft/block/BlockBasePressurePlate.java index fd83e1f1..6c25ea16 100755 --- a/src/game/java/net/minecraft/block/BlockBasePressurePlate.java +++ b/src/game/java/net/minecraft/block/BlockBasePressurePlate.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockBeacon.java b/src/game/java/net/minecraft/block/BlockBeacon.java index d66465b9..b8414d13 100755 --- a/src/game/java/net/minecraft/block/BlockBeacon.java +++ b/src/game/java/net/minecraft/block/BlockBeacon.java @@ -24,7 +24,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockBed.java b/src/game/java/net/minecraft/block/BlockBed.java index 52885281..57c2a193 100755 --- a/src/game/java/net/minecraft/block/BlockBed.java +++ b/src/game/java/net/minecraft/block/BlockBed.java @@ -30,7 +30,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockBookshelf.java b/src/game/java/net/minecraft/block/BlockBookshelf.java index 2b5f7402..8888a523 100755 --- a/src/game/java/net/minecraft/block/BlockBookshelf.java +++ b/src/game/java/net/minecraft/block/BlockBookshelf.java @@ -14,7 +14,7 @@ import net.minecraft.item.Item; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockBreakable.java b/src/game/java/net/minecraft/block/BlockBreakable.java index 32931eaf..3c1d482b 100755 --- a/src/game/java/net/minecraft/block/BlockBreakable.java +++ b/src/game/java/net/minecraft/block/BlockBreakable.java @@ -14,7 +14,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockBrewingStand.java b/src/game/java/net/minecraft/block/BlockBrewingStand.java index 2a4d3fae..d2613498 100755 --- a/src/game/java/net/minecraft/block/BlockBrewingStand.java +++ b/src/game/java/net/minecraft/block/BlockBrewingStand.java @@ -33,7 +33,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockBush.java b/src/game/java/net/minecraft/block/BlockBush.java index c8039f27..002f97d3 100755 --- a/src/game/java/net/minecraft/block/BlockBush.java +++ b/src/game/java/net/minecraft/block/BlockBush.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockButton.java b/src/game/java/net/minecraft/block/BlockButton.java index c9776ac9..2eeea02d 100755 --- a/src/game/java/net/minecraft/block/BlockButton.java +++ b/src/game/java/net/minecraft/block/BlockButton.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockButtonStone.java b/src/game/java/net/minecraft/block/BlockButtonStone.java index 767b56a7..b1bb5326 100755 --- a/src/game/java/net/minecraft/block/BlockButtonStone.java +++ b/src/game/java/net/minecraft/block/BlockButtonStone.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockButtonWood.java b/src/game/java/net/minecraft/block/BlockButtonWood.java index 0f282ffd..093d3846 100755 --- a/src/game/java/net/minecraft/block/BlockButtonWood.java +++ b/src/game/java/net/minecraft/block/BlockButtonWood.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockCactus.java b/src/game/java/net/minecraft/block/BlockCactus.java index 04681b1a..5a8afeaa 100755 --- a/src/game/java/net/minecraft/block/BlockCactus.java +++ b/src/game/java/net/minecraft/block/BlockCactus.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockCake.java b/src/game/java/net/minecraft/block/BlockCake.java index 96e7a444..b4691c9a 100755 --- a/src/game/java/net/minecraft/block/BlockCake.java +++ b/src/game/java/net/minecraft/block/BlockCake.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockCarpet.java b/src/game/java/net/minecraft/block/BlockCarpet.java index 41902e35..1c9f8df0 100755 --- a/src/game/java/net/minecraft/block/BlockCarpet.java +++ b/src/game/java/net/minecraft/block/BlockCarpet.java @@ -26,7 +26,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockCarrot.java b/src/game/java/net/minecraft/block/BlockCarrot.java index f2c91677..f428a776 100755 --- a/src/game/java/net/minecraft/block/BlockCarrot.java +++ b/src/game/java/net/minecraft/block/BlockCarrot.java @@ -9,7 +9,7 @@ import net.minecraft.item.Item; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockCauldron.java b/src/game/java/net/minecraft/block/BlockCauldron.java index 24fde302..12193956 100755 --- a/src/game/java/net/minecraft/block/BlockCauldron.java +++ b/src/game/java/net/minecraft/block/BlockCauldron.java @@ -32,7 +32,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockChest.java b/src/game/java/net/minecraft/block/BlockChest.java index f5e8fdaf..d490fd9f 100755 --- a/src/game/java/net/minecraft/block/BlockChest.java +++ b/src/game/java/net/minecraft/block/BlockChest.java @@ -34,7 +34,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockClay.java b/src/game/java/net/minecraft/block/BlockClay.java index 9eb0f65b..1e917644 100755 --- a/src/game/java/net/minecraft/block/BlockClay.java +++ b/src/game/java/net/minecraft/block/BlockClay.java @@ -14,7 +14,7 @@ import net.minecraft.item.Item; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockCocoa.java b/src/game/java/net/minecraft/block/BlockCocoa.java index c789ae94..2da3f87c 100755 --- a/src/game/java/net/minecraft/block/BlockCocoa.java +++ b/src/game/java/net/minecraft/block/BlockCocoa.java @@ -26,7 +26,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockColored.java b/src/game/java/net/minecraft/block/BlockColored.java index 3d414905..7f5c06b0 100755 --- a/src/game/java/net/minecraft/block/BlockColored.java +++ b/src/game/java/net/minecraft/block/BlockColored.java @@ -19,7 +19,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockCommandBlock.java b/src/game/java/net/minecraft/block/BlockCommandBlock.java index 9b1de4d0..94832017 100755 --- a/src/game/java/net/minecraft/block/BlockCommandBlock.java +++ b/src/game/java/net/minecraft/block/BlockCommandBlock.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockCompressedPowered.java b/src/game/java/net/minecraft/block/BlockCompressedPowered.java index d08ef238..2e2b2942 100755 --- a/src/game/java/net/minecraft/block/BlockCompressedPowered.java +++ b/src/game/java/net/minecraft/block/BlockCompressedPowered.java @@ -13,7 +13,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockContainer.java b/src/game/java/net/minecraft/block/BlockContainer.java index 0525b98f..5efc381d 100755 --- a/src/game/java/net/minecraft/block/BlockContainer.java +++ b/src/game/java/net/minecraft/block/BlockContainer.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockCrops.java b/src/game/java/net/minecraft/block/BlockCrops.java index fed0ab42..5293e37d 100755 --- a/src/game/java/net/minecraft/block/BlockCrops.java +++ b/src/game/java/net/minecraft/block/BlockCrops.java @@ -21,7 +21,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockDaylightDetector.java b/src/game/java/net/minecraft/block/BlockDaylightDetector.java index 4b0d8ba0..68c412c8 100755 --- a/src/game/java/net/minecraft/block/BlockDaylightDetector.java +++ b/src/game/java/net/minecraft/block/BlockDaylightDetector.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockDeadBush.java b/src/game/java/net/minecraft/block/BlockDeadBush.java index 8727792e..0463683e 100755 --- a/src/game/java/net/minecraft/block/BlockDeadBush.java +++ b/src/game/java/net/minecraft/block/BlockDeadBush.java @@ -21,7 +21,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockDirectional.java b/src/game/java/net/minecraft/block/BlockDirectional.java index 78ae0759..cf3a0e94 100755 --- a/src/game/java/net/minecraft/block/BlockDirectional.java +++ b/src/game/java/net/minecraft/block/BlockDirectional.java @@ -11,7 +11,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockDirt.java b/src/game/java/net/minecraft/block/BlockDirt.java index f91ae9e7..68b89e1f 100755 --- a/src/game/java/net/minecraft/block/BlockDirt.java +++ b/src/game/java/net/minecraft/block/BlockDirt.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockDispenser.java b/src/game/java/net/minecraft/block/BlockDispenser.java index 934f7611..93938698 100755 --- a/src/game/java/net/minecraft/block/BlockDispenser.java +++ b/src/game/java/net/minecraft/block/BlockDispenser.java @@ -35,7 +35,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockDoor.java b/src/game/java/net/minecraft/block/BlockDoor.java index 0a6e868e..9a015e8a 100755 --- a/src/game/java/net/minecraft/block/BlockDoor.java +++ b/src/game/java/net/minecraft/block/BlockDoor.java @@ -30,7 +30,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockDoublePlant.java b/src/game/java/net/minecraft/block/BlockDoublePlant.java index bce102dd..a4f373ff 100755 --- a/src/game/java/net/minecraft/block/BlockDoublePlant.java +++ b/src/game/java/net/minecraft/block/BlockDoublePlant.java @@ -30,7 +30,7 @@ import net.minecraft.world.biome.BiomeColorHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockDoubleStoneSlab.java b/src/game/java/net/minecraft/block/BlockDoubleStoneSlab.java index 164300fd..7c0564ba 100755 --- a/src/game/java/net/minecraft/block/BlockDoubleStoneSlab.java +++ b/src/game/java/net/minecraft/block/BlockDoubleStoneSlab.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockDoubleStoneSlabNew.java b/src/game/java/net/minecraft/block/BlockDoubleStoneSlabNew.java index 7a918c33..2e0e0b33 100755 --- a/src/game/java/net/minecraft/block/BlockDoubleStoneSlabNew.java +++ b/src/game/java/net/minecraft/block/BlockDoubleStoneSlabNew.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockDoubleWoodSlab.java b/src/game/java/net/minecraft/block/BlockDoubleWoodSlab.java index 1bbbbca9..a2c88187 100755 --- a/src/game/java/net/minecraft/block/BlockDoubleWoodSlab.java +++ b/src/game/java/net/minecraft/block/BlockDoubleWoodSlab.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockDragonEgg.java b/src/game/java/net/minecraft/block/BlockDragonEgg.java index 6d887490..aa0254cb 100755 --- a/src/game/java/net/minecraft/block/BlockDragonEgg.java +++ b/src/game/java/net/minecraft/block/BlockDragonEgg.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockDropper.java b/src/game/java/net/minecraft/block/BlockDropper.java index ce97d6d0..ac97b77f 100755 --- a/src/game/java/net/minecraft/block/BlockDropper.java +++ b/src/game/java/net/minecraft/block/BlockDropper.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockDynamicLiquid.java b/src/game/java/net/minecraft/block/BlockDynamicLiquid.java index c35e2ce6..a07de593 100755 --- a/src/game/java/net/minecraft/block/BlockDynamicLiquid.java +++ b/src/game/java/net/minecraft/block/BlockDynamicLiquid.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockEnchantmentTable.java b/src/game/java/net/minecraft/block/BlockEnchantmentTable.java index 8f89ec4d..7bd76930 100755 --- a/src/game/java/net/minecraft/block/BlockEnchantmentTable.java +++ b/src/game/java/net/minecraft/block/BlockEnchantmentTable.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockEndPortal.java b/src/game/java/net/minecraft/block/BlockEndPortal.java index 9b1d06f5..37cedf33 100755 --- a/src/game/java/net/minecraft/block/BlockEndPortal.java +++ b/src/game/java/net/minecraft/block/BlockEndPortal.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockEndPortalFrame.java b/src/game/java/net/minecraft/block/BlockEndPortalFrame.java index 1955085e..e03c905c 100755 --- a/src/game/java/net/minecraft/block/BlockEndPortalFrame.java +++ b/src/game/java/net/minecraft/block/BlockEndPortalFrame.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockEnderChest.java b/src/game/java/net/minecraft/block/BlockEnderChest.java index 76ca86e5..a292d5ee 100755 --- a/src/game/java/net/minecraft/block/BlockEnderChest.java +++ b/src/game/java/net/minecraft/block/BlockEnderChest.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockEventData.java b/src/game/java/net/minecraft/block/BlockEventData.java index 13a361ed..364ca989 100755 --- a/src/game/java/net/minecraft/block/BlockEventData.java +++ b/src/game/java/net/minecraft/block/BlockEventData.java @@ -8,7 +8,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockFalling.java b/src/game/java/net/minecraft/block/BlockFalling.java index 8f80daa6..4bc4f426 100755 --- a/src/game/java/net/minecraft/block/BlockFalling.java +++ b/src/game/java/net/minecraft/block/BlockFalling.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockFarmland.java b/src/game/java/net/minecraft/block/BlockFarmland.java index 17bf6d1b..d1a224ff 100755 --- a/src/game/java/net/minecraft/block/BlockFarmland.java +++ b/src/game/java/net/minecraft/block/BlockFarmland.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockFence.java b/src/game/java/net/minecraft/block/BlockFence.java index f9b42448..43129759 100755 --- a/src/game/java/net/minecraft/block/BlockFence.java +++ b/src/game/java/net/minecraft/block/BlockFence.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockFenceGate.java b/src/game/java/net/minecraft/block/BlockFenceGate.java index 12f25461..5efc8971 100755 --- a/src/game/java/net/minecraft/block/BlockFenceGate.java +++ b/src/game/java/net/minecraft/block/BlockFenceGate.java @@ -21,7 +21,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockFire.java b/src/game/java/net/minecraft/block/BlockFire.java index 3368218a..0d4f176a 100755 --- a/src/game/java/net/minecraft/block/BlockFire.java +++ b/src/game/java/net/minecraft/block/BlockFire.java @@ -1,9 +1,9 @@ package net.minecraft.block; -import java.util.Map; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; -import com.google.common.collect.Maps; +import com.carrotsearch.hppc.ObjectIntIdentityHashMap; +import com.carrotsearch.hppc.ObjectIntMap; import net.minecraft.block.material.MapColor; import net.minecraft.block.material.Material; @@ -28,7 +28,7 @@ import net.minecraft.world.WorldProviderEnd; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -51,8 +51,8 @@ public class BlockFire extends Block { public static final PropertyBool SOUTH = PropertyBool.create("south"); public static final PropertyBool WEST = PropertyBool.create("west"); public static final PropertyInteger UPPER = PropertyInteger.create("upper", 0, 2); - private final Map encouragements = Maps.newIdentityHashMap(); - private final Map flammabilities = Maps.newIdentityHashMap(); + private final ObjectIntMap encouragements = new ObjectIntIdentityHashMap<>(); + private final ObjectIntMap flammabilities = new ObjectIntIdentityHashMap<>(); /**+ * Get the actual Block state of this Block at the given @@ -132,8 +132,8 @@ public class BlockFire extends Block { } public void setFireInfo(Block blockIn, int encouragement, int flammability) { - this.encouragements.put(blockIn, Integer.valueOf(encouragement)); - this.flammabilities.put(blockIn, Integer.valueOf(flammability)); + this.encouragements.put(blockIn, encouragement); + this.flammabilities.put(blockIn, flammability); } public AxisAlignedBB getCollisionBoundingBox(World var1, BlockPos var2, IBlockState var3) { @@ -226,6 +226,8 @@ public class BlockFire extends Block { } BlockPos blockpos1 = blockpos.add(j, l, k); + if (!world.isBlockLoaded(blockpos1)) + continue; int j1 = this.getNeighborEncouragement(world, blockpos1); if (j1 > 0) { int k1 = (j1 + 40 + world.getDifficulty().getDifficultyId() * 7) / (i + 30); @@ -264,19 +266,20 @@ public class BlockFire extends Block { } private int getFlammability(Block blockIn) { - Integer integer = (Integer) this.flammabilities.get(blockIn); - return integer == null ? 0 : integer.intValue(); + return this.flammabilities.getOrDefault(blockIn, 0); } private int getEncouragement(Block blockIn) { - Integer integer = (Integer) this.encouragements.get(blockIn); - return integer == null ? 0 : integer.intValue(); + return this.encouragements.getOrDefault(blockIn, 0); } private void catchOnFire(World worldIn, BlockPos pos, int chance, EaglercraftRandom random, int age) { - int i = this.getFlammability(worldIn.getBlockState(pos).getBlock()); + IBlockState iblockstate = worldIn.getBlockStateIfLoaded(pos); + if (iblockstate == null) { + return; + } + int i = this.getFlammability(iblockstate.getBlock()); if (random.nextInt(chance) < i) { - IBlockState iblockstate = worldIn.getBlockState(pos); if (random.nextInt(age + 10) < 5 && !worldIn.canLightningStrike(pos)) { int j = age + random.nextInt(5) / 4; if (j > 15) { @@ -315,8 +318,12 @@ public class BlockFire extends Block { int i = 0; EnumFacing[] facings = EnumFacing._VALUES; + BlockPos tmp = new BlockPos(0, 0, 0); for (int j = 0; j < facings.length; ++j) { - i = Math.max(this.getEncouragement(worldIn.getBlockState(pos.offset(facings[j])).getBlock()), i); + IBlockState type = worldIn.getBlockStateIfLoaded(pos.offsetEvenFaster(facings[j], tmp)); + if (type != null) { + i = Math.max(this.getEncouragement(type.getBlock()), i); + } } return i; diff --git a/src/game/java/net/minecraft/block/BlockFlower.java b/src/game/java/net/minecraft/block/BlockFlower.java index d73ba6e4..4ab5a445 100755 --- a/src/game/java/net/minecraft/block/BlockFlower.java +++ b/src/game/java/net/minecraft/block/BlockFlower.java @@ -23,7 +23,7 @@ import net.minecraft.util.IStringSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockFlowerPot.java b/src/game/java/net/minecraft/block/BlockFlowerPot.java index 3482ddb3..e334b083 100755 --- a/src/game/java/net/minecraft/block/BlockFlowerPot.java +++ b/src/game/java/net/minecraft/block/BlockFlowerPot.java @@ -31,7 +31,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockFurnace.java b/src/game/java/net/minecraft/block/BlockFurnace.java index 35821986..2f2acba8 100755 --- a/src/game/java/net/minecraft/block/BlockFurnace.java +++ b/src/game/java/net/minecraft/block/BlockFurnace.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockGlass.java b/src/game/java/net/minecraft/block/BlockGlass.java index 2c0cc1ad..5c7d1c1a 100755 --- a/src/game/java/net/minecraft/block/BlockGlass.java +++ b/src/game/java/net/minecraft/block/BlockGlass.java @@ -12,7 +12,7 @@ import net.minecraft.util.EnumWorldBlockLayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockGlowstone.java b/src/game/java/net/minecraft/block/BlockGlowstone.java index 5de1582b..929a1195 100755 --- a/src/game/java/net/minecraft/block/BlockGlowstone.java +++ b/src/game/java/net/minecraft/block/BlockGlowstone.java @@ -16,7 +16,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockGrass.java b/src/game/java/net/minecraft/block/BlockGrass.java index 77cd8bdd..01860310 100755 --- a/src/game/java/net/minecraft/block/BlockGrass.java +++ b/src/game/java/net/minecraft/block/BlockGrass.java @@ -23,7 +23,7 @@ import net.minecraft.world.biome.BiomeColorHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockGravel.java b/src/game/java/net/minecraft/block/BlockGravel.java index 38c30052..cddd6e67 100755 --- a/src/game/java/net/minecraft/block/BlockGravel.java +++ b/src/game/java/net/minecraft/block/BlockGravel.java @@ -13,7 +13,7 @@ import net.minecraft.item.Item; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockHalfStoneSlab.java b/src/game/java/net/minecraft/block/BlockHalfStoneSlab.java index e0201a27..2eaac83b 100755 --- a/src/game/java/net/minecraft/block/BlockHalfStoneSlab.java +++ b/src/game/java/net/minecraft/block/BlockHalfStoneSlab.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockHalfStoneSlabNew.java b/src/game/java/net/minecraft/block/BlockHalfStoneSlabNew.java index aa0fdbe8..3ef3b78c 100755 --- a/src/game/java/net/minecraft/block/BlockHalfStoneSlabNew.java +++ b/src/game/java/net/minecraft/block/BlockHalfStoneSlabNew.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockHalfWoodSlab.java b/src/game/java/net/minecraft/block/BlockHalfWoodSlab.java index 7c0c3703..cc9cf13f 100755 --- a/src/game/java/net/minecraft/block/BlockHalfWoodSlab.java +++ b/src/game/java/net/minecraft/block/BlockHalfWoodSlab.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockHardenedClay.java b/src/game/java/net/minecraft/block/BlockHardenedClay.java index 57915476..a1b28620 100755 --- a/src/game/java/net/minecraft/block/BlockHardenedClay.java +++ b/src/game/java/net/minecraft/block/BlockHardenedClay.java @@ -11,7 +11,7 @@ import net.minecraft.creativetab.CreativeTabs; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockHay.java b/src/game/java/net/minecraft/block/BlockHay.java index f4f9e8df..7b261fc0 100755 --- a/src/game/java/net/minecraft/block/BlockHay.java +++ b/src/game/java/net/minecraft/block/BlockHay.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockHopper.java b/src/game/java/net/minecraft/block/BlockHopper.java index 4874da92..1ea31179 100755 --- a/src/game/java/net/minecraft/block/BlockHopper.java +++ b/src/game/java/net/minecraft/block/BlockHopper.java @@ -34,7 +34,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockHugeMushroom.java b/src/game/java/net/minecraft/block/BlockHugeMushroom.java index 6ba543e7..ea0a2a4d 100755 --- a/src/game/java/net/minecraft/block/BlockHugeMushroom.java +++ b/src/game/java/net/minecraft/block/BlockHugeMushroom.java @@ -21,7 +21,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockIce.java b/src/game/java/net/minecraft/block/BlockIce.java index b08d495c..fbc65999 100755 --- a/src/game/java/net/minecraft/block/BlockIce.java +++ b/src/game/java/net/minecraft/block/BlockIce.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockJukebox.java b/src/game/java/net/minecraft/block/BlockJukebox.java index d31df2d4..c2776ce3 100755 --- a/src/game/java/net/minecraft/block/BlockJukebox.java +++ b/src/game/java/net/minecraft/block/BlockJukebox.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockLadder.java b/src/game/java/net/minecraft/block/BlockLadder.java index 3a569979..31ac8555 100755 --- a/src/game/java/net/minecraft/block/BlockLadder.java +++ b/src/game/java/net/minecraft/block/BlockLadder.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockLeaves.java b/src/game/java/net/minecraft/block/BlockLeaves.java index dc534462..fd3903e8 100755 --- a/src/game/java/net/minecraft/block/BlockLeaves.java +++ b/src/game/java/net/minecraft/block/BlockLeaves.java @@ -23,7 +23,7 @@ import net.minecraft.world.biome.BiomeColorHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockLeavesBase.java b/src/game/java/net/minecraft/block/BlockLeavesBase.java index fa8db7e5..08577d0c 100755 --- a/src/game/java/net/minecraft/block/BlockLeavesBase.java +++ b/src/game/java/net/minecraft/block/BlockLeavesBase.java @@ -11,7 +11,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockLever.java b/src/game/java/net/minecraft/block/BlockLever.java index 4948a666..47213698 100755 --- a/src/game/java/net/minecraft/block/BlockLever.java +++ b/src/game/java/net/minecraft/block/BlockLever.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockLilyPad.java b/src/game/java/net/minecraft/block/BlockLilyPad.java index b5fa49d0..07913621 100755 --- a/src/game/java/net/minecraft/block/BlockLilyPad.java +++ b/src/game/java/net/minecraft/block/BlockLilyPad.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockLiquid.java b/src/game/java/net/minecraft/block/BlockLiquid.java index bc0d1b90..c0acf93b 100755 --- a/src/game/java/net/minecraft/block/BlockLiquid.java +++ b/src/game/java/net/minecraft/block/BlockLiquid.java @@ -27,7 +27,7 @@ import net.minecraft.world.biome.BiomeColorHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockLog.java b/src/game/java/net/minecraft/block/BlockLog.java index acacc000..3b9390b2 100755 --- a/src/game/java/net/minecraft/block/BlockLog.java +++ b/src/game/java/net/minecraft/block/BlockLog.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockMelon.java b/src/game/java/net/minecraft/block/BlockMelon.java index dabba802..93450e89 100755 --- a/src/game/java/net/minecraft/block/BlockMelon.java +++ b/src/game/java/net/minecraft/block/BlockMelon.java @@ -15,7 +15,7 @@ import net.minecraft.item.Item; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockMobSpawner.java b/src/game/java/net/minecraft/block/BlockMobSpawner.java index 4a12be09..d9e8ed5f 100755 --- a/src/game/java/net/minecraft/block/BlockMobSpawner.java +++ b/src/game/java/net/minecraft/block/BlockMobSpawner.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockMushroom.java b/src/game/java/net/minecraft/block/BlockMushroom.java index 95dcb1d0..21496ac0 100755 --- a/src/game/java/net/minecraft/block/BlockMushroom.java +++ b/src/game/java/net/minecraft/block/BlockMushroom.java @@ -14,7 +14,7 @@ import net.minecraft.world.gen.feature.WorldGenBigMushroom; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockMycelium.java b/src/game/java/net/minecraft/block/BlockMycelium.java index c2f6a3de..7c622aec 100755 --- a/src/game/java/net/minecraft/block/BlockMycelium.java +++ b/src/game/java/net/minecraft/block/BlockMycelium.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockNetherBrick.java b/src/game/java/net/minecraft/block/BlockNetherBrick.java index 0210337b..5f78c7d0 100755 --- a/src/game/java/net/minecraft/block/BlockNetherBrick.java +++ b/src/game/java/net/minecraft/block/BlockNetherBrick.java @@ -11,7 +11,7 @@ import net.minecraft.creativetab.CreativeTabs; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockNetherWart.java b/src/game/java/net/minecraft/block/BlockNetherWart.java index bd2df534..24b47098 100755 --- a/src/game/java/net/minecraft/block/BlockNetherWart.java +++ b/src/game/java/net/minecraft/block/BlockNetherWart.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockNetherrack.java b/src/game/java/net/minecraft/block/BlockNetherrack.java index 614c0585..7766eb84 100755 --- a/src/game/java/net/minecraft/block/BlockNetherrack.java +++ b/src/game/java/net/minecraft/block/BlockNetherrack.java @@ -11,7 +11,7 @@ import net.minecraft.creativetab.CreativeTabs; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockNewLeaf.java b/src/game/java/net/minecraft/block/BlockNewLeaf.java index c39a36c8..40379071 100755 --- a/src/game/java/net/minecraft/block/BlockNewLeaf.java +++ b/src/game/java/net/minecraft/block/BlockNewLeaf.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockNewLog.java b/src/game/java/net/minecraft/block/BlockNewLog.java index 4d46cd92..52b64837 100755 --- a/src/game/java/net/minecraft/block/BlockNewLog.java +++ b/src/game/java/net/minecraft/block/BlockNewLog.java @@ -19,7 +19,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockNote.java b/src/game/java/net/minecraft/block/BlockNote.java index 00886e87..3c6274bc 100755 --- a/src/game/java/net/minecraft/block/BlockNote.java +++ b/src/game/java/net/minecraft/block/BlockNote.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockObsidian.java b/src/game/java/net/minecraft/block/BlockObsidian.java index 8caae1e8..a3ae2f2a 100755 --- a/src/game/java/net/minecraft/block/BlockObsidian.java +++ b/src/game/java/net/minecraft/block/BlockObsidian.java @@ -15,7 +15,7 @@ import net.minecraft.item.Item; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockOldLeaf.java b/src/game/java/net/minecraft/block/BlockOldLeaf.java index 3634f38a..a1804c2e 100755 --- a/src/game/java/net/minecraft/block/BlockOldLeaf.java +++ b/src/game/java/net/minecraft/block/BlockOldLeaf.java @@ -26,7 +26,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockOldLog.java b/src/game/java/net/minecraft/block/BlockOldLog.java index 8dbe8c78..448c2fa5 100755 --- a/src/game/java/net/minecraft/block/BlockOldLog.java +++ b/src/game/java/net/minecraft/block/BlockOldLog.java @@ -19,7 +19,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockOre.java b/src/game/java/net/minecraft/block/BlockOre.java index b063d923..a0e444c8 100755 --- a/src/game/java/net/minecraft/block/BlockOre.java +++ b/src/game/java/net/minecraft/block/BlockOre.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockPackedIce.java b/src/game/java/net/minecraft/block/BlockPackedIce.java index 257804df..03c4453b 100755 --- a/src/game/java/net/minecraft/block/BlockPackedIce.java +++ b/src/game/java/net/minecraft/block/BlockPackedIce.java @@ -11,7 +11,7 @@ import net.minecraft.creativetab.CreativeTabs; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockPane.java b/src/game/java/net/minecraft/block/BlockPane.java index 404bb875..05afad4a 100755 --- a/src/game/java/net/minecraft/block/BlockPane.java +++ b/src/game/java/net/minecraft/block/BlockPane.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockPistonBase.java b/src/game/java/net/minecraft/block/BlockPistonBase.java index 1703ebe2..75791b37 100755 --- a/src/game/java/net/minecraft/block/BlockPistonBase.java +++ b/src/game/java/net/minecraft/block/BlockPistonBase.java @@ -29,7 +29,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockPistonExtension.java b/src/game/java/net/minecraft/block/BlockPistonExtension.java index 37ecccee..2e1898aa 100755 --- a/src/game/java/net/minecraft/block/BlockPistonExtension.java +++ b/src/game/java/net/minecraft/block/BlockPistonExtension.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockPistonMoving.java b/src/game/java/net/minecraft/block/BlockPistonMoving.java index bdf1f057..73f05661 100755 --- a/src/game/java/net/minecraft/block/BlockPistonMoving.java +++ b/src/game/java/net/minecraft/block/BlockPistonMoving.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockPlanks.java b/src/game/java/net/minecraft/block/BlockPlanks.java index ba0109d9..b3fc20d7 100755 --- a/src/game/java/net/minecraft/block/BlockPlanks.java +++ b/src/game/java/net/minecraft/block/BlockPlanks.java @@ -19,7 +19,7 @@ import net.minecraft.util.IStringSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockPortal.java b/src/game/java/net/minecraft/block/BlockPortal.java index e2e499ab..dedef301 100755 --- a/src/game/java/net/minecraft/block/BlockPortal.java +++ b/src/game/java/net/minecraft/block/BlockPortal.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockPotato.java b/src/game/java/net/minecraft/block/BlockPotato.java index b6ebed95..1d004848 100755 --- a/src/game/java/net/minecraft/block/BlockPotato.java +++ b/src/game/java/net/minecraft/block/BlockPotato.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockPressurePlate.java b/src/game/java/net/minecraft/block/BlockPressurePlate.java index 0e7f7684..838f0cb8 100755 --- a/src/game/java/net/minecraft/block/BlockPressurePlate.java +++ b/src/game/java/net/minecraft/block/BlockPressurePlate.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockPressurePlateWeighted.java b/src/game/java/net/minecraft/block/BlockPressurePlateWeighted.java index 29ed717a..25696ed2 100755 --- a/src/game/java/net/minecraft/block/BlockPressurePlateWeighted.java +++ b/src/game/java/net/minecraft/block/BlockPressurePlateWeighted.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockPrismarine.java b/src/game/java/net/minecraft/block/BlockPrismarine.java index 9addcbe5..8d6fa7a9 100755 --- a/src/game/java/net/minecraft/block/BlockPrismarine.java +++ b/src/game/java/net/minecraft/block/BlockPrismarine.java @@ -20,7 +20,7 @@ import net.minecraft.util.StatCollector; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockPumpkin.java b/src/game/java/net/minecraft/block/BlockPumpkin.java index 98c8488d..2656e62e 100755 --- a/src/game/java/net/minecraft/block/BlockPumpkin.java +++ b/src/game/java/net/minecraft/block/BlockPumpkin.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockQuartz.java b/src/game/java/net/minecraft/block/BlockQuartz.java index 1685a638..2a447f69 100755 --- a/src/game/java/net/minecraft/block/BlockQuartz.java +++ b/src/game/java/net/minecraft/block/BlockQuartz.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockRail.java b/src/game/java/net/minecraft/block/BlockRail.java index 1d5eeb3a..7a3f17a4 100755 --- a/src/game/java/net/minecraft/block/BlockRail.java +++ b/src/game/java/net/minecraft/block/BlockRail.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockRailBase.java b/src/game/java/net/minecraft/block/BlockRailBase.java index 8f0884a5..39aba226 100755 --- a/src/game/java/net/minecraft/block/BlockRailBase.java +++ b/src/game/java/net/minecraft/block/BlockRailBase.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockRailDetector.java b/src/game/java/net/minecraft/block/BlockRailDetector.java index 61299c96..50bd7964 100755 --- a/src/game/java/net/minecraft/block/BlockRailDetector.java +++ b/src/game/java/net/minecraft/block/BlockRailDetector.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockRailPowered.java b/src/game/java/net/minecraft/block/BlockRailPowered.java index d2a136d6..63622ff5 100755 --- a/src/game/java/net/minecraft/block/BlockRailPowered.java +++ b/src/game/java/net/minecraft/block/BlockRailPowered.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockRedFlower.java b/src/game/java/net/minecraft/block/BlockRedFlower.java index 183fef29..c1b543b1 100755 --- a/src/game/java/net/minecraft/block/BlockRedFlower.java +++ b/src/game/java/net/minecraft/block/BlockRedFlower.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockRedSandstone.java b/src/game/java/net/minecraft/block/BlockRedSandstone.java index 1d7861a8..9e5c8581 100755 --- a/src/game/java/net/minecraft/block/BlockRedSandstone.java +++ b/src/game/java/net/minecraft/block/BlockRedSandstone.java @@ -18,7 +18,7 @@ import net.minecraft.util.IStringSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockRedstoneComparator.java b/src/game/java/net/minecraft/block/BlockRedstoneComparator.java index 95db0406..b22b30ac 100755 --- a/src/game/java/net/minecraft/block/BlockRedstoneComparator.java +++ b/src/game/java/net/minecraft/block/BlockRedstoneComparator.java @@ -34,7 +34,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockRedstoneDiode.java b/src/game/java/net/minecraft/block/BlockRedstoneDiode.java index 0087315b..c0c88e61 100755 --- a/src/game/java/net/minecraft/block/BlockRedstoneDiode.java +++ b/src/game/java/net/minecraft/block/BlockRedstoneDiode.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockRedstoneLight.java b/src/game/java/net/minecraft/block/BlockRedstoneLight.java index 041eee05..39f318f3 100755 --- a/src/game/java/net/minecraft/block/BlockRedstoneLight.java +++ b/src/game/java/net/minecraft/block/BlockRedstoneLight.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockRedstoneOre.java b/src/game/java/net/minecraft/block/BlockRedstoneOre.java index 0647819d..7eeafe7d 100755 --- a/src/game/java/net/minecraft/block/BlockRedstoneOre.java +++ b/src/game/java/net/minecraft/block/BlockRedstoneOre.java @@ -21,7 +21,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockRedstoneRepeater.java b/src/game/java/net/minecraft/block/BlockRedstoneRepeater.java index 9a2c2253..4521ca13 100755 --- a/src/game/java/net/minecraft/block/BlockRedstoneRepeater.java +++ b/src/game/java/net/minecraft/block/BlockRedstoneRepeater.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockRedstoneTorch.java b/src/game/java/net/minecraft/block/BlockRedstoneTorch.java index 06c751c1..41f95eba 100755 --- a/src/game/java/net/minecraft/block/BlockRedstoneTorch.java +++ b/src/game/java/net/minecraft/block/BlockRedstoneTorch.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -119,11 +119,16 @@ public class BlockRedstoneTorch extends BlockTorch { public void updateTick(World world, BlockPos blockpos, IBlockState iblockstate, EaglercraftRandom random) { boolean flag = this.shouldBeOff(world, blockpos, iblockstate); - List list = (List) toggles.get(world); + List list = toggles.get(world); - while (list != null && !list.isEmpty() - && world.getTotalWorldTime() - ((BlockRedstoneTorch.Toggle) list.get(0)).time > 60L) { - list.remove(0); + if (list != null) { + int index = 0; + while (index < list.size() && world.getTotalWorldTime() - list.get(index).time > 60L) { + index++; + } + if (index > 0) { + list.subList(0, index).clear(); + } } if (this.isOn) { diff --git a/src/game/java/net/minecraft/block/BlockRedstoneWire.java b/src/game/java/net/minecraft/block/BlockRedstoneWire.java index f10fcd43..dfda4290 100755 --- a/src/game/java/net/minecraft/block/BlockRedstoneWire.java +++ b/src/game/java/net/minecraft/block/BlockRedstoneWire.java @@ -33,7 +33,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockReed.java b/src/game/java/net/minecraft/block/BlockReed.java index c81df456..93e20669 100755 --- a/src/game/java/net/minecraft/block/BlockReed.java +++ b/src/game/java/net/minecraft/block/BlockReed.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockRotatedPillar.java b/src/game/java/net/minecraft/block/BlockRotatedPillar.java index 3bead051..45dbe586 100755 --- a/src/game/java/net/minecraft/block/BlockRotatedPillar.java +++ b/src/game/java/net/minecraft/block/BlockRotatedPillar.java @@ -11,7 +11,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockSand.java b/src/game/java/net/minecraft/block/BlockSand.java index 58e1175d..e8998e8d 100755 --- a/src/game/java/net/minecraft/block/BlockSand.java +++ b/src/game/java/net/minecraft/block/BlockSand.java @@ -18,7 +18,7 @@ import net.minecraft.util.IStringSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockSandStone.java b/src/game/java/net/minecraft/block/BlockSandStone.java index f5c249f5..a6d92d42 100755 --- a/src/game/java/net/minecraft/block/BlockSandStone.java +++ b/src/game/java/net/minecraft/block/BlockSandStone.java @@ -19,7 +19,7 @@ import net.minecraft.util.IStringSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockSapling.java b/src/game/java/net/minecraft/block/BlockSapling.java index 5d261c8a..4cd3860d 100755 --- a/src/game/java/net/minecraft/block/BlockSapling.java +++ b/src/game/java/net/minecraft/block/BlockSapling.java @@ -31,7 +31,7 @@ import net.minecraft.world.gen.feature.WorldGenerator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockSeaLantern.java b/src/game/java/net/minecraft/block/BlockSeaLantern.java index 9ed67660..a831d151 100755 --- a/src/game/java/net/minecraft/block/BlockSeaLantern.java +++ b/src/game/java/net/minecraft/block/BlockSeaLantern.java @@ -16,7 +16,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockSign.java b/src/game/java/net/minecraft/block/BlockSign.java index d5498ac7..c7f9c91c 100755 --- a/src/game/java/net/minecraft/block/BlockSign.java +++ b/src/game/java/net/minecraft/block/BlockSign.java @@ -21,7 +21,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockSilverfish.java b/src/game/java/net/minecraft/block/BlockSilverfish.java index 75b234be..f37650a1 100755 --- a/src/game/java/net/minecraft/block/BlockSilverfish.java +++ b/src/game/java/net/minecraft/block/BlockSilverfish.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockSkull.java b/src/game/java/net/minecraft/block/BlockSkull.java index a0ff2eae..1b589dfe 100755 --- a/src/game/java/net/minecraft/block/BlockSkull.java +++ b/src/game/java/net/minecraft/block/BlockSkull.java @@ -43,7 +43,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockSlab.java b/src/game/java/net/minecraft/block/BlockSlab.java index 83220663..0ec9269c 100755 --- a/src/game/java/net/minecraft/block/BlockSlab.java +++ b/src/game/java/net/minecraft/block/BlockSlab.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockSlime.java b/src/game/java/net/minecraft/block/BlockSlime.java index 41144bb0..76c0bc76 100755 --- a/src/game/java/net/minecraft/block/BlockSlime.java +++ b/src/game/java/net/minecraft/block/BlockSlime.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockSnow.java b/src/game/java/net/minecraft/block/BlockSnow.java index 7bf7fab6..2bbbc327 100755 --- a/src/game/java/net/minecraft/block/BlockSnow.java +++ b/src/game/java/net/minecraft/block/BlockSnow.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockSnowBlock.java b/src/game/java/net/minecraft/block/BlockSnowBlock.java index 7cc01215..072436d4 100755 --- a/src/game/java/net/minecraft/block/BlockSnowBlock.java +++ b/src/game/java/net/minecraft/block/BlockSnowBlock.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockSoulSand.java b/src/game/java/net/minecraft/block/BlockSoulSand.java index a67f82cf..37a2f4b7 100755 --- a/src/game/java/net/minecraft/block/BlockSoulSand.java +++ b/src/game/java/net/minecraft/block/BlockSoulSand.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockSourceImpl.java b/src/game/java/net/minecraft/block/BlockSourceImpl.java index a1603629..559e8207 100755 --- a/src/game/java/net/minecraft/block/BlockSourceImpl.java +++ b/src/game/java/net/minecraft/block/BlockSourceImpl.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockSponge.java b/src/game/java/net/minecraft/block/BlockSponge.java index 51241692..736fdd35 100755 --- a/src/game/java/net/minecraft/block/BlockSponge.java +++ b/src/game/java/net/minecraft/block/BlockSponge.java @@ -29,7 +29,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockStainedGlass.java b/src/game/java/net/minecraft/block/BlockStainedGlass.java index f964f980..ff3d9fec 100755 --- a/src/game/java/net/minecraft/block/BlockStainedGlass.java +++ b/src/game/java/net/minecraft/block/BlockStainedGlass.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockStainedGlassPane.java b/src/game/java/net/minecraft/block/BlockStainedGlassPane.java index e1db700c..debca6d2 100755 --- a/src/game/java/net/minecraft/block/BlockStainedGlassPane.java +++ b/src/game/java/net/minecraft/block/BlockStainedGlassPane.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockStairs.java b/src/game/java/net/minecraft/block/BlockStairs.java index dc1cf48e..d86d0508 100755 --- a/src/game/java/net/minecraft/block/BlockStairs.java +++ b/src/game/java/net/minecraft/block/BlockStairs.java @@ -34,7 +34,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockStandingSign.java b/src/game/java/net/minecraft/block/BlockStandingSign.java index 61c303af..5109b157 100755 --- a/src/game/java/net/minecraft/block/BlockStandingSign.java +++ b/src/game/java/net/minecraft/block/BlockStandingSign.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockStaticLiquid.java b/src/game/java/net/minecraft/block/BlockStaticLiquid.java index e1d95030..704c3232 100755 --- a/src/game/java/net/minecraft/block/BlockStaticLiquid.java +++ b/src/game/java/net/minecraft/block/BlockStaticLiquid.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockStem.java b/src/game/java/net/minecraft/block/BlockStem.java index 2c0f7eed..5a08b34a 100755 --- a/src/game/java/net/minecraft/block/BlockStem.java +++ b/src/game/java/net/minecraft/block/BlockStem.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockStone.java b/src/game/java/net/minecraft/block/BlockStone.java index 0978de1e..2f6e56af 100755 --- a/src/game/java/net/minecraft/block/BlockStone.java +++ b/src/game/java/net/minecraft/block/BlockStone.java @@ -22,7 +22,7 @@ import net.minecraft.util.StatCollector; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockStoneBrick.java b/src/game/java/net/minecraft/block/BlockStoneBrick.java index 136e9f3c..a29812e6 100755 --- a/src/game/java/net/minecraft/block/BlockStoneBrick.java +++ b/src/game/java/net/minecraft/block/BlockStoneBrick.java @@ -18,7 +18,7 @@ import net.minecraft.util.IStringSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockStoneSlab.java b/src/game/java/net/minecraft/block/BlockStoneSlab.java index 10a5547e..d0cf124f 100755 --- a/src/game/java/net/minecraft/block/BlockStoneSlab.java +++ b/src/game/java/net/minecraft/block/BlockStoneSlab.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockStoneSlabNew.java b/src/game/java/net/minecraft/block/BlockStoneSlabNew.java index 00c8ad6f..b7f1bccc 100755 --- a/src/game/java/net/minecraft/block/BlockStoneSlabNew.java +++ b/src/game/java/net/minecraft/block/BlockStoneSlabNew.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockTNT.java b/src/game/java/net/minecraft/block/BlockTNT.java index e2088d14..f9fa0528 100755 --- a/src/game/java/net/minecraft/block/BlockTNT.java +++ b/src/game/java/net/minecraft/block/BlockTNT.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockTallGrass.java b/src/game/java/net/minecraft/block/BlockTallGrass.java index 36d77fc6..671d9e49 100755 --- a/src/game/java/net/minecraft/block/BlockTallGrass.java +++ b/src/game/java/net/minecraft/block/BlockTallGrass.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockTorch.java b/src/game/java/net/minecraft/block/BlockTorch.java index 633b2133..94b7c664 100755 --- a/src/game/java/net/minecraft/block/BlockTorch.java +++ b/src/game/java/net/minecraft/block/BlockTorch.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockTrapDoor.java b/src/game/java/net/minecraft/block/BlockTrapDoor.java index 77f4a73f..17d196aa 100755 --- a/src/game/java/net/minecraft/block/BlockTrapDoor.java +++ b/src/game/java/net/minecraft/block/BlockTrapDoor.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockTripWire.java b/src/game/java/net/minecraft/block/BlockTripWire.java index b9eb57b9..0675dbfd 100755 --- a/src/game/java/net/minecraft/block/BlockTripWire.java +++ b/src/game/java/net/minecraft/block/BlockTripWire.java @@ -26,7 +26,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockTripWireHook.java b/src/game/java/net/minecraft/block/BlockTripWireHook.java index dcfa9fe7..07e73e9a 100755 --- a/src/game/java/net/minecraft/block/BlockTripWireHook.java +++ b/src/game/java/net/minecraft/block/BlockTripWireHook.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockVine.java b/src/game/java/net/minecraft/block/BlockVine.java index 179beece..52e28ea6 100755 --- a/src/game/java/net/minecraft/block/BlockVine.java +++ b/src/game/java/net/minecraft/block/BlockVine.java @@ -30,7 +30,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockWall.java b/src/game/java/net/minecraft/block/BlockWall.java index 1e259991..ab1e80f5 100755 --- a/src/game/java/net/minecraft/block/BlockWall.java +++ b/src/game/java/net/minecraft/block/BlockWall.java @@ -26,7 +26,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockWallSign.java b/src/game/java/net/minecraft/block/BlockWallSign.java index e8b456b1..ebb92813 100755 --- a/src/game/java/net/minecraft/block/BlockWallSign.java +++ b/src/game/java/net/minecraft/block/BlockWallSign.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockWeb.java b/src/game/java/net/minecraft/block/BlockWeb.java index 4eeb6b94..b1327155 100755 --- a/src/game/java/net/minecraft/block/BlockWeb.java +++ b/src/game/java/net/minecraft/block/BlockWeb.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockWoodSlab.java b/src/game/java/net/minecraft/block/BlockWoodSlab.java index ade4b630..36adf26a 100755 --- a/src/game/java/net/minecraft/block/BlockWoodSlab.java +++ b/src/game/java/net/minecraft/block/BlockWoodSlab.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockWorkbench.java b/src/game/java/net/minecraft/block/BlockWorkbench.java index 8915cf22..30fdca31 100755 --- a/src/game/java/net/minecraft/block/BlockWorkbench.java +++ b/src/game/java/net/minecraft/block/BlockWorkbench.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/BlockYellowFlower.java b/src/game/java/net/minecraft/block/BlockYellowFlower.java index 16281600..01e6054b 100755 --- a/src/game/java/net/minecraft/block/BlockYellowFlower.java +++ b/src/game/java/net/minecraft/block/BlockYellowFlower.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/IGrowable.java b/src/game/java/net/minecraft/block/IGrowable.java index 7bd9898f..83615370 100755 --- a/src/game/java/net/minecraft/block/IGrowable.java +++ b/src/game/java/net/minecraft/block/IGrowable.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/ITileEntityProvider.java b/src/game/java/net/minecraft/block/ITileEntityProvider.java index 84b818d9..3501cebd 100755 --- a/src/game/java/net/minecraft/block/ITileEntityProvider.java +++ b/src/game/java/net/minecraft/block/ITileEntityProvider.java @@ -9,7 +9,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/material/MapColor.java b/src/game/java/net/minecraft/block/material/MapColor.java index c7aebfd0..7700bfe6 100755 --- a/src/game/java/net/minecraft/block/material/MapColor.java +++ b/src/game/java/net/minecraft/block/material/MapColor.java @@ -6,7 +6,7 @@ package net.minecraft.block.material; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/material/Material.java b/src/game/java/net/minecraft/block/material/Material.java index 65ccc935..8597e516 100755 --- a/src/game/java/net/minecraft/block/material/Material.java +++ b/src/game/java/net/minecraft/block/material/Material.java @@ -6,7 +6,7 @@ package net.minecraft.block.material; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/material/MaterialLiquid.java b/src/game/java/net/minecraft/block/material/MaterialLiquid.java index 8fd027b0..1352c8fa 100755 --- a/src/game/java/net/minecraft/block/material/MaterialLiquid.java +++ b/src/game/java/net/minecraft/block/material/MaterialLiquid.java @@ -6,7 +6,7 @@ package net.minecraft.block.material; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/material/MaterialLogic.java b/src/game/java/net/minecraft/block/material/MaterialLogic.java index 79699c8c..92c65c47 100755 --- a/src/game/java/net/minecraft/block/material/MaterialLogic.java +++ b/src/game/java/net/minecraft/block/material/MaterialLogic.java @@ -6,7 +6,7 @@ package net.minecraft.block.material; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/material/MaterialPortal.java b/src/game/java/net/minecraft/block/material/MaterialPortal.java index 1cad7e2d..9d83b983 100755 --- a/src/game/java/net/minecraft/block/material/MaterialPortal.java +++ b/src/game/java/net/minecraft/block/material/MaterialPortal.java @@ -6,7 +6,7 @@ package net.minecraft.block.material; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/material/MaterialTransparent.java b/src/game/java/net/minecraft/block/material/MaterialTransparent.java index f58e96c8..5dda0587 100755 --- a/src/game/java/net/minecraft/block/material/MaterialTransparent.java +++ b/src/game/java/net/minecraft/block/material/MaterialTransparent.java @@ -6,7 +6,7 @@ package net.minecraft.block.material; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/properties/IProperty.java b/src/game/java/net/minecraft/block/properties/IProperty.java index fc2abe7d..3dd89864 100755 --- a/src/game/java/net/minecraft/block/properties/IProperty.java +++ b/src/game/java/net/minecraft/block/properties/IProperty.java @@ -8,7 +8,7 @@ import java.util.Collection; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/properties/PropertyBool.java b/src/game/java/net/minecraft/block/properties/PropertyBool.java index 0a983315..a375dc86 100755 --- a/src/game/java/net/minecraft/block/properties/PropertyBool.java +++ b/src/game/java/net/minecraft/block/properties/PropertyBool.java @@ -10,7 +10,7 @@ import com.google.common.collect.ImmutableSet; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/properties/PropertyDirection.java b/src/game/java/net/minecraft/block/properties/PropertyDirection.java index 9cc316eb..84fe198f 100755 --- a/src/game/java/net/minecraft/block/properties/PropertyDirection.java +++ b/src/game/java/net/minecraft/block/properties/PropertyDirection.java @@ -15,7 +15,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/properties/PropertyEnum.java b/src/game/java/net/minecraft/block/properties/PropertyEnum.java index 9f999e29..893fd208 100755 --- a/src/game/java/net/minecraft/block/properties/PropertyEnum.java +++ b/src/game/java/net/minecraft/block/properties/PropertyEnum.java @@ -18,7 +18,7 @@ import net.minecraft.util.IStringSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/properties/PropertyHelper.java b/src/game/java/net/minecraft/block/properties/PropertyHelper.java index 3f1c61ab..2518d2c3 100755 --- a/src/game/java/net/minecraft/block/properties/PropertyHelper.java +++ b/src/game/java/net/minecraft/block/properties/PropertyHelper.java @@ -8,7 +8,7 @@ import com.google.common.base.Objects; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/properties/PropertyInteger.java b/src/game/java/net/minecraft/block/properties/PropertyInteger.java index 4d826cc9..67e7fbcb 100755 --- a/src/game/java/net/minecraft/block/properties/PropertyInteger.java +++ b/src/game/java/net/minecraft/block/properties/PropertyInteger.java @@ -12,7 +12,7 @@ import com.google.common.collect.Sets; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/state/BlockPistonStructureHelper.java b/src/game/java/net/minecraft/block/state/BlockPistonStructureHelper.java index 3c5dfc2c..69101068 100755 --- a/src/game/java/net/minecraft/block/state/BlockPistonStructureHelper.java +++ b/src/game/java/net/minecraft/block/state/BlockPistonStructureHelper.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/state/BlockState.java b/src/game/java/net/minecraft/block/state/BlockState.java index 8f4b42a1..b949ab95 100755 --- a/src/game/java/net/minecraft/block/state/BlockState.java +++ b/src/game/java/net/minecraft/block/state/BlockState.java @@ -32,7 +32,7 @@ import net.minecraft.util.MapPopulator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/state/BlockStateBase.java b/src/game/java/net/minecraft/block/state/BlockStateBase.java index 87d32356..0ecc915e 100755 --- a/src/game/java/net/minecraft/block/state/BlockStateBase.java +++ b/src/game/java/net/minecraft/block/state/BlockStateBase.java @@ -17,7 +17,7 @@ import net.minecraft.block.properties.IProperty; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/state/BlockWorldState.java b/src/game/java/net/minecraft/block/state/BlockWorldState.java index fdfe5201..48827700 100755 --- a/src/game/java/net/minecraft/block/state/BlockWorldState.java +++ b/src/game/java/net/minecraft/block/state/BlockWorldState.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/state/IBlockState.java b/src/game/java/net/minecraft/block/state/IBlockState.java index 20cd5850..05df0ed3 100755 --- a/src/game/java/net/minecraft/block/state/IBlockState.java +++ b/src/game/java/net/minecraft/block/state/IBlockState.java @@ -13,7 +13,7 @@ import net.minecraft.block.properties.IProperty; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/state/pattern/BlockHelper.java b/src/game/java/net/minecraft/block/state/pattern/BlockHelper.java index edeb5565..a53638bb 100755 --- a/src/game/java/net/minecraft/block/state/pattern/BlockHelper.java +++ b/src/game/java/net/minecraft/block/state/pattern/BlockHelper.java @@ -11,7 +11,7 @@ import net.minecraft.block.state.IBlockState; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/state/pattern/BlockPattern.java b/src/game/java/net/minecraft/block/state/pattern/BlockPattern.java index 2bd9330a..af6d68fe 100755 --- a/src/game/java/net/minecraft/block/state/pattern/BlockPattern.java +++ b/src/game/java/net/minecraft/block/state/pattern/BlockPattern.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/state/pattern/BlockStateHelper.java b/src/game/java/net/minecraft/block/state/pattern/BlockStateHelper.java index 48ea7e81..992c1aef 100755 --- a/src/game/java/net/minecraft/block/state/pattern/BlockStateHelper.java +++ b/src/game/java/net/minecraft/block/state/pattern/BlockStateHelper.java @@ -17,7 +17,7 @@ import net.minecraft.block.state.IBlockState; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/block/state/pattern/FactoryBlockPattern.java b/src/game/java/net/minecraft/block/state/pattern/FactoryBlockPattern.java index bd882033..f3265584 100755 --- a/src/game/java/net/minecraft/block/state/pattern/FactoryBlockPattern.java +++ b/src/game/java/net/minecraft/block/state/pattern/FactoryBlockPattern.java @@ -2,16 +2,16 @@ package net.minecraft.block.state.pattern; import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.Map.Entry; import org.apache.commons.lang3.StringUtils; +import com.carrotsearch.hppc.CharObjectHashMap; +import com.carrotsearch.hppc.CharObjectMap; +import com.carrotsearch.hppc.cursors.CharObjectCursor; import com.google.common.base.Joiner; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import net.minecraft.block.state.BlockWorldState; @@ -21,7 +21,7 @@ import net.minecraft.block.state.BlockWorldState; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -38,12 +38,12 @@ import net.minecraft.block.state.BlockWorldState; public class FactoryBlockPattern { private static final Joiner COMMA_JOIN = Joiner.on(","); private final List depth = Lists.newArrayList(); - private final Map> symbolMap = Maps.newHashMap(); + private final CharObjectMap> symbolMap = new CharObjectHashMap<>(); private int aisleHeight; private int rowWidth; private FactoryBlockPattern() { - this.symbolMap.put(Character.valueOf(' '), Predicates.alwaysTrue()); + this.symbolMap.put(' ', Predicates.alwaysTrue()); } public FactoryBlockPattern aisle(String... aisle) { @@ -68,8 +68,8 @@ public class FactoryBlockPattern { char[] achar = s.toCharArray(); for (int j = 0; j < achar.length; ++j) { char c0 = achar[j]; - if (!this.symbolMap.containsKey(Character.valueOf(c0))) { - this.symbolMap.put(Character.valueOf(c0), null); + if (!this.symbolMap.containsKey(c0)) { + this.symbolMap.put(c0, null); } } } @@ -87,7 +87,7 @@ public class FactoryBlockPattern { } public FactoryBlockPattern where(char symbol, Predicate blockMatcher) { - this.symbolMap.put(Character.valueOf(symbol), blockMatcher); + this.symbolMap.put(symbol, blockMatcher); return this; } @@ -102,8 +102,7 @@ public class FactoryBlockPattern { for (int i = 0; i < this.depth.size(); ++i) { for (int j = 0; j < this.aisleHeight; ++j) { for (int k = 0; k < this.rowWidth; ++k) { - apredicate[i][j][k] = (Predicate) this.symbolMap - .get(Character.valueOf(((String[]) this.depth.get(i))[j].charAt(k))); + apredicate[i][j][k] = this.symbolMap.get(((String[]) this.depth.get(i))[j].charAt(k)); } } } @@ -114,9 +113,9 @@ public class FactoryBlockPattern { private void checkMissingPredicates() { ArrayList arraylist = Lists.newArrayList(); - for (Entry entry : this.symbolMap.entrySet()) { - if (entry.getValue() == null) { - arraylist.add(entry.getKey()); + for (CharObjectCursor> entry : this.symbolMap) { + if (entry.value == null) { + arraylist.add(entry.key); } } diff --git a/src/game/java/net/minecraft/client/ClientBrandRetriever.java b/src/game/java/net/minecraft/client/ClientBrandRetriever.java index 232956c7..05a7dece 100755 --- a/src/game/java/net/minecraft/client/ClientBrandRetriever.java +++ b/src/game/java/net/minecraft/client/ClientBrandRetriever.java @@ -6,7 +6,7 @@ package net.minecraft.client; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/LoadingScreenRenderer.java b/src/game/java/net/minecraft/client/LoadingScreenRenderer.java index 597a5388..11a10df5 100755 --- a/src/game/java/net/minecraft/client/LoadingScreenRenderer.java +++ b/src/game/java/net/minecraft/client/LoadingScreenRenderer.java @@ -18,7 +18,7 @@ import net.minecraft.util.MinecraftError; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/Minecraft.java b/src/game/java/net/minecraft/client/Minecraft.java index 933aff53..1dabd777 100755 --- a/src/game/java/net/minecraft/client/Minecraft.java +++ b/src/game/java/net/minecraft/client/Minecraft.java @@ -206,7 +206,7 @@ import net.minecraft.world.storage.ISaveFormat; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/audio/GuardianSound.java b/src/game/java/net/minecraft/client/audio/GuardianSound.java index b88fd273..16ee7cd9 100755 --- a/src/game/java/net/minecraft/client/audio/GuardianSound.java +++ b/src/game/java/net/minecraft/client/audio/GuardianSound.java @@ -9,7 +9,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/audio/ISound.java b/src/game/java/net/minecraft/client/audio/ISound.java index 5df9e099..21a3a735 100755 --- a/src/game/java/net/minecraft/client/audio/ISound.java +++ b/src/game/java/net/minecraft/client/audio/ISound.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/audio/ISoundEventAccessor.java b/src/game/java/net/minecraft/client/audio/ISoundEventAccessor.java index bfa4d74d..cba466b7 100755 --- a/src/game/java/net/minecraft/client/audio/ISoundEventAccessor.java +++ b/src/game/java/net/minecraft/client/audio/ISoundEventAccessor.java @@ -6,7 +6,7 @@ package net.minecraft.client.audio; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/audio/ITickableSound.java b/src/game/java/net/minecraft/client/audio/ITickableSound.java index 66dc660e..b290ae73 100755 --- a/src/game/java/net/minecraft/client/audio/ITickableSound.java +++ b/src/game/java/net/minecraft/client/audio/ITickableSound.java @@ -8,7 +8,7 @@ import net.minecraft.util.ITickable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/audio/MovingSound.java b/src/game/java/net/minecraft/client/audio/MovingSound.java index 7b312aeb..2c5ced65 100755 --- a/src/game/java/net/minecraft/client/audio/MovingSound.java +++ b/src/game/java/net/minecraft/client/audio/MovingSound.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/audio/MovingSoundMinecart.java b/src/game/java/net/minecraft/client/audio/MovingSoundMinecart.java index 5abe13c8..3d970321 100755 --- a/src/game/java/net/minecraft/client/audio/MovingSoundMinecart.java +++ b/src/game/java/net/minecraft/client/audio/MovingSoundMinecart.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/audio/MovingSoundMinecartRiding.java b/src/game/java/net/minecraft/client/audio/MovingSoundMinecartRiding.java index 876c5625..9a560f2e 100755 --- a/src/game/java/net/minecraft/client/audio/MovingSoundMinecartRiding.java +++ b/src/game/java/net/minecraft/client/audio/MovingSoundMinecartRiding.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/audio/MusicTicker.java b/src/game/java/net/minecraft/client/audio/MusicTicker.java index 1f5a8cdf..f377fac1 100755 --- a/src/game/java/net/minecraft/client/audio/MusicTicker.java +++ b/src/game/java/net/minecraft/client/audio/MusicTicker.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/audio/PositionedSound.java b/src/game/java/net/minecraft/client/audio/PositionedSound.java index a6790292..13f2a2e8 100755 --- a/src/game/java/net/minecraft/client/audio/PositionedSound.java +++ b/src/game/java/net/minecraft/client/audio/PositionedSound.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/audio/PositionedSoundRecord.java b/src/game/java/net/minecraft/client/audio/PositionedSoundRecord.java index 7814e6ee..1ec00d7d 100755 --- a/src/game/java/net/minecraft/client/audio/PositionedSoundRecord.java +++ b/src/game/java/net/minecraft/client/audio/PositionedSoundRecord.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/audio/SoundCategory.java b/src/game/java/net/minecraft/client/audio/SoundCategory.java index d9e22bef..51d637ff 100755 --- a/src/game/java/net/minecraft/client/audio/SoundCategory.java +++ b/src/game/java/net/minecraft/client/audio/SoundCategory.java @@ -2,6 +2,8 @@ package net.minecraft.client.audio; import java.util.Map; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import com.google.common.collect.Maps; /**+ @@ -10,7 +12,7 @@ import com.google.common.collect.Maps; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -31,7 +33,7 @@ public enum SoundCategory { public static final SoundCategory[] _VALUES = values(); private static final Map NAME_CATEGORY_MAP = Maps.newHashMap(); - private static final Map ID_CATEGORY_MAP = Maps.newHashMap(); + private static final IntObjectMap ID_CATEGORY_MAP = new IntObjectHashMap<>(); private final String categoryName; private final int categoryId; @@ -57,12 +59,12 @@ public enum SoundCategory { for (int i = 0; i < categories.length; ++i) { SoundCategory soundcategory = categories[i]; if (NAME_CATEGORY_MAP.containsKey(soundcategory.getCategoryName()) - || ID_CATEGORY_MAP.containsKey(Integer.valueOf(soundcategory.getCategoryId()))) { + || ID_CATEGORY_MAP.containsKey(soundcategory.getCategoryId())) { throw new Error("Clash in Sound Category ID & Name pools! Cannot insert " + soundcategory); } NAME_CATEGORY_MAP.put(soundcategory.getCategoryName(), soundcategory); - ID_CATEGORY_MAP.put(Integer.valueOf(soundcategory.getCategoryId()), soundcategory); + ID_CATEGORY_MAP.put(soundcategory.getCategoryId(), soundcategory); } } diff --git a/src/game/java/net/minecraft/client/audio/SoundEventAccessor.java b/src/game/java/net/minecraft/client/audio/SoundEventAccessor.java index f23d7e40..1b87f566 100755 --- a/src/game/java/net/minecraft/client/audio/SoundEventAccessor.java +++ b/src/game/java/net/minecraft/client/audio/SoundEventAccessor.java @@ -6,7 +6,7 @@ package net.minecraft.client.audio; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/audio/SoundEventAccessorComposite.java b/src/game/java/net/minecraft/client/audio/SoundEventAccessorComposite.java index 3911f6a9..08d20016 100755 --- a/src/game/java/net/minecraft/client/audio/SoundEventAccessorComposite.java +++ b/src/game/java/net/minecraft/client/audio/SoundEventAccessorComposite.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/audio/SoundHandler.java b/src/game/java/net/minecraft/client/audio/SoundHandler.java index 445b9d3d..9ec3b9d2 100755 --- a/src/game/java/net/minecraft/client/audio/SoundHandler.java +++ b/src/game/java/net/minecraft/client/audio/SoundHandler.java @@ -31,7 +31,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/audio/SoundList.java b/src/game/java/net/minecraft/client/audio/SoundList.java index 87e26fcd..316f4b8f 100755 --- a/src/game/java/net/minecraft/client/audio/SoundList.java +++ b/src/game/java/net/minecraft/client/audio/SoundList.java @@ -10,7 +10,7 @@ import com.google.common.collect.Lists; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/audio/SoundListSerializer.java b/src/game/java/net/minecraft/client/audio/SoundListSerializer.java index 14f37e4f..5855e313 100755 --- a/src/game/java/net/minecraft/client/audio/SoundListSerializer.java +++ b/src/game/java/net/minecraft/client/audio/SoundListSerializer.java @@ -13,7 +13,7 @@ import net.lax1dude.eaglercraft.v1_8.json.JSONTypeDeserializer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/audio/SoundPoolEntry.java b/src/game/java/net/minecraft/client/audio/SoundPoolEntry.java index 4fd65772..a3787b93 100755 --- a/src/game/java/net/minecraft/client/audio/SoundPoolEntry.java +++ b/src/game/java/net/minecraft/client/audio/SoundPoolEntry.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/audio/SoundRegistry.java b/src/game/java/net/minecraft/client/audio/SoundRegistry.java index 61ee6d30..30bf6325 100755 --- a/src/game/java/net/minecraft/client/audio/SoundRegistry.java +++ b/src/game/java/net/minecraft/client/audio/SoundRegistry.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/entity/AbstractClientPlayer.java b/src/game/java/net/minecraft/client/entity/AbstractClientPlayer.java index 4259135c..ac7f50d5 100755 --- a/src/game/java/net/minecraft/client/entity/AbstractClientPlayer.java +++ b/src/game/java/net/minecraft/client/entity/AbstractClientPlayer.java @@ -26,7 +26,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/entity/EntityOtherPlayerMP.java b/src/game/java/net/minecraft/client/entity/EntityOtherPlayerMP.java index f7e668a1..6d58c872 100755 --- a/src/game/java/net/minecraft/client/entity/EntityOtherPlayerMP.java +++ b/src/game/java/net/minecraft/client/entity/EntityOtherPlayerMP.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/entity/EntityPlayerSP.java b/src/game/java/net/minecraft/client/entity/EntityPlayerSP.java index 9e8f30b1..36d99a89 100755 --- a/src/game/java/net/minecraft/client/entity/EntityPlayerSP.java +++ b/src/game/java/net/minecraft/client/entity/EntityPlayerSP.java @@ -61,7 +61,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/ChatLine.java b/src/game/java/net/minecraft/client/gui/ChatLine.java index 1bd8e16b..d392f40d 100755 --- a/src/game/java/net/minecraft/client/gui/ChatLine.java +++ b/src/game/java/net/minecraft/client/gui/ChatLine.java @@ -10,7 +10,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/FontRenderer.java b/src/game/java/net/minecraft/client/gui/FontRenderer.java index 7ec37e22..5d26062e 100755 --- a/src/game/java/net/minecraft/client/gui/FontRenderer.java +++ b/src/game/java/net/minecraft/client/gui/FontRenderer.java @@ -4,6 +4,8 @@ import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.List; + +import net.lax1dude.eaglercraft.v1_8.EaglerBidiReorder; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; import net.lax1dude.eaglercraft.v1_8.HString; @@ -28,7 +30,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -329,21 +331,6 @@ public class FontRenderer implements IResourceManagerReloadListener { return i; } - /**+ - * Apply Unicode Bidirectional Algorithm to string and return a - * new possibly reordered string for visual rendering. - */ - private String bidiReorder(String parString1) { -// try { -// Bidi bidi = new Bidi((new ArabicShaping(8)).shape(parString1), 127); -// bidi.setReorderingMode(0); -// return bidi.writeReordered(2); -// } catch (ArabicShapingException var3) { -// return parString1; -// } - return parString1; - } - /**+ * Reset all style flag fields in the class to false; called at * the start of string rendering @@ -501,7 +488,7 @@ public class FontRenderer implements IResourceManagerReloadListener { */ private int renderStringAligned(String text, int x, int y, int wrapWidth, int color, boolean parFlag) { if (this.bidiFlag) { - int i = this.getStringWidth(this.bidiReorder(text)); + int i = this.getStringWidth(EaglerBidiReorder.bidiReorder(text)); x = x + wrapWidth - i; } @@ -518,7 +505,7 @@ public class FontRenderer implements IResourceManagerReloadListener { this.posY = y; } else { if (this.bidiFlag) { - text = this.bidiReorder(text); + text = EaglerBidiReorder.bidiReorder(text); } if ((color & -67108864) == 0) { diff --git a/src/game/java/net/minecraft/client/gui/Gui.java b/src/game/java/net/minecraft/client/gui/Gui.java index c2fc356f..bc7f23ea 100755 --- a/src/game/java/net/minecraft/client/gui/Gui.java +++ b/src/game/java/net/minecraft/client/gui/Gui.java @@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiButton.java b/src/game/java/net/minecraft/client/gui/GuiButton.java index 54dc4be0..4f5dc626 100755 --- a/src/game/java/net/minecraft/client/gui/GuiButton.java +++ b/src/game/java/net/minecraft/client/gui/GuiButton.java @@ -16,7 +16,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiButtonLanguage.java b/src/game/java/net/minecraft/client/gui/GuiButtonLanguage.java index 850e4468..74c99ff2 100755 --- a/src/game/java/net/minecraft/client/gui/GuiButtonLanguage.java +++ b/src/game/java/net/minecraft/client/gui/GuiButtonLanguage.java @@ -11,7 +11,7 @@ import net.minecraft.client.Minecraft; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiChat.java b/src/game/java/net/minecraft/client/gui/GuiChat.java index 48e28fca..19f639fe 100755 --- a/src/game/java/net/minecraft/client/gui/GuiChat.java +++ b/src/game/java/net/minecraft/client/gui/GuiChat.java @@ -31,7 +31,7 @@ import net.minecraft.util.MovingObjectPosition; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiCommandBlock.java b/src/game/java/net/minecraft/client/gui/GuiCommandBlock.java index 78f9efb3..b9b0344a 100755 --- a/src/game/java/net/minecraft/client/gui/GuiCommandBlock.java +++ b/src/game/java/net/minecraft/client/gui/GuiCommandBlock.java @@ -17,7 +17,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiConfirmOpenLink.java b/src/game/java/net/minecraft/client/gui/GuiConfirmOpenLink.java index faa42d05..9bca025b 100755 --- a/src/game/java/net/minecraft/client/gui/GuiConfirmOpenLink.java +++ b/src/game/java/net/minecraft/client/gui/GuiConfirmOpenLink.java @@ -8,7 +8,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiControls.java b/src/game/java/net/minecraft/client/gui/GuiControls.java index da3fb4a7..0e08d1f1 100755 --- a/src/game/java/net/minecraft/client/gui/GuiControls.java +++ b/src/game/java/net/minecraft/client/gui/GuiControls.java @@ -13,7 +13,7 @@ import net.minecraft.client.settings.KeyBinding; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiCreateFlatWorld.java b/src/game/java/net/minecraft/client/gui/GuiCreateFlatWorld.java index bb66925e..1c571761 100755 --- a/src/game/java/net/minecraft/client/gui/GuiCreateFlatWorld.java +++ b/src/game/java/net/minecraft/client/gui/GuiCreateFlatWorld.java @@ -23,7 +23,7 @@ import net.minecraft.world.gen.FlatLayerInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiCreateWorld.java b/src/game/java/net/minecraft/client/gui/GuiCreateWorld.java index 16b1b6ec..8f31695a 100755 --- a/src/game/java/net/minecraft/client/gui/GuiCreateWorld.java +++ b/src/game/java/net/minecraft/client/gui/GuiCreateWorld.java @@ -18,7 +18,7 @@ import org.apache.commons.lang3.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiCustomizeSkin.java b/src/game/java/net/minecraft/client/gui/GuiCustomizeSkin.java index 4a2d4857..6b58328a 100755 --- a/src/game/java/net/minecraft/client/gui/GuiCustomizeSkin.java +++ b/src/game/java/net/minecraft/client/gui/GuiCustomizeSkin.java @@ -9,7 +9,7 @@ import net.minecraft.entity.player.EnumPlayerModelParts; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiCustomizeWorldScreen.java b/src/game/java/net/minecraft/client/gui/GuiCustomizeWorldScreen.java index 5a124068..8b040b97 100755 --- a/src/game/java/net/minecraft/client/gui/GuiCustomizeWorldScreen.java +++ b/src/game/java/net/minecraft/client/gui/GuiCustomizeWorldScreen.java @@ -22,7 +22,7 @@ import net.minecraft.world.gen.ChunkProviderSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiDisconnected.java b/src/game/java/net/minecraft/client/gui/GuiDisconnected.java index b37fa256..05a450a9 100755 --- a/src/game/java/net/minecraft/client/gui/GuiDisconnected.java +++ b/src/game/java/net/minecraft/client/gui/GuiDisconnected.java @@ -15,7 +15,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiDownloadTerrain.java b/src/game/java/net/minecraft/client/gui/GuiDownloadTerrain.java index b530ba0f..45c13dde 100755 --- a/src/game/java/net/minecraft/client/gui/GuiDownloadTerrain.java +++ b/src/game/java/net/minecraft/client/gui/GuiDownloadTerrain.java @@ -10,7 +10,7 @@ import net.minecraft.network.play.client.C00PacketKeepAlive; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiEnchantment.java b/src/game/java/net/minecraft/client/gui/GuiEnchantment.java index 4475cec3..afc50c42 100755 --- a/src/game/java/net/minecraft/client/gui/GuiEnchantment.java +++ b/src/game/java/net/minecraft/client/gui/GuiEnchantment.java @@ -32,7 +32,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiErrorScreen.java b/src/game/java/net/minecraft/client/gui/GuiErrorScreen.java index 083a688c..6f1387c3 100755 --- a/src/game/java/net/minecraft/client/gui/GuiErrorScreen.java +++ b/src/game/java/net/minecraft/client/gui/GuiErrorScreen.java @@ -8,7 +8,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiFlatPresets.java b/src/game/java/net/minecraft/client/gui/GuiFlatPresets.java index b261f8d9..4a7ea5bb 100755 --- a/src/game/java/net/minecraft/client/gui/GuiFlatPresets.java +++ b/src/game/java/net/minecraft/client/gui/GuiFlatPresets.java @@ -29,7 +29,7 @@ import net.minecraft.world.gen.FlatLayerInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiGameOver.java b/src/game/java/net/minecraft/client/gui/GuiGameOver.java index 73577b52..e8db0d14 100755 --- a/src/game/java/net/minecraft/client/gui/GuiGameOver.java +++ b/src/game/java/net/minecraft/client/gui/GuiGameOver.java @@ -11,7 +11,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiHopper.java b/src/game/java/net/minecraft/client/gui/GuiHopper.java index 263ea609..35ca080d 100755 --- a/src/game/java/net/minecraft/client/gui/GuiHopper.java +++ b/src/game/java/net/minecraft/client/gui/GuiHopper.java @@ -14,7 +14,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiIngame.java b/src/game/java/net/minecraft/client/gui/GuiIngame.java index 89223159..ff09a1b8 100755 --- a/src/game/java/net/minecraft/client/gui/GuiIngame.java +++ b/src/game/java/net/minecraft/client/gui/GuiIngame.java @@ -64,7 +64,7 @@ import net.minecraft.world.border.WorldBorder; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiIngameMenu.java b/src/game/java/net/minecraft/client/gui/GuiIngameMenu.java index c5bc76d0..cc92c330 100755 --- a/src/game/java/net/minecraft/client/gui/GuiIngameMenu.java +++ b/src/game/java/net/minecraft/client/gui/GuiIngameMenu.java @@ -33,7 +33,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiKeyBindingList.java b/src/game/java/net/minecraft/client/gui/GuiKeyBindingList.java index d5c3fba8..755a822d 100755 --- a/src/game/java/net/minecraft/client/gui/GuiKeyBindingList.java +++ b/src/game/java/net/minecraft/client/gui/GuiKeyBindingList.java @@ -16,7 +16,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiLabel.java b/src/game/java/net/minecraft/client/gui/GuiLabel.java index 0657b9a9..dd716b60 100755 --- a/src/game/java/net/minecraft/client/gui/GuiLabel.java +++ b/src/game/java/net/minecraft/client/gui/GuiLabel.java @@ -16,7 +16,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiLanguage.java b/src/game/java/net/minecraft/client/gui/GuiLanguage.java index f62de6b6..900b01a3 100755 --- a/src/game/java/net/minecraft/client/gui/GuiLanguage.java +++ b/src/game/java/net/minecraft/client/gui/GuiLanguage.java @@ -18,7 +18,7 @@ import net.minecraft.client.settings.GameSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiListButton.java b/src/game/java/net/minecraft/client/gui/GuiListButton.java index 95680cd0..9ab5543a 100755 --- a/src/game/java/net/minecraft/client/gui/GuiListButton.java +++ b/src/game/java/net/minecraft/client/gui/GuiListButton.java @@ -9,7 +9,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiListExtended.java b/src/game/java/net/minecraft/client/gui/GuiListExtended.java index 83b44ae9..fa5eb56b 100755 --- a/src/game/java/net/minecraft/client/gui/GuiListExtended.java +++ b/src/game/java/net/minecraft/client/gui/GuiListExtended.java @@ -8,7 +8,7 @@ import net.minecraft.client.Minecraft; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiLockIconButton.java b/src/game/java/net/minecraft/client/gui/GuiLockIconButton.java index 88982a2a..81866484 100755 --- a/src/game/java/net/minecraft/client/gui/GuiLockIconButton.java +++ b/src/game/java/net/minecraft/client/gui/GuiLockIconButton.java @@ -9,7 +9,7 @@ import net.minecraft.client.Minecraft; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiMainMenu.java b/src/game/java/net/minecraft/client/gui/GuiMainMenu.java index 8a470b81..0c0bfafe 100755 --- a/src/game/java/net/minecraft/client/gui/GuiMainMenu.java +++ b/src/game/java/net/minecraft/client/gui/GuiMainMenu.java @@ -53,7 +53,7 @@ import net.minecraft.world.storage.ISaveFormat; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiMemoryErrorScreen.java b/src/game/java/net/minecraft/client/gui/GuiMemoryErrorScreen.java index b07c6c22..7f55854a 100755 --- a/src/game/java/net/minecraft/client/gui/GuiMemoryErrorScreen.java +++ b/src/game/java/net/minecraft/client/gui/GuiMemoryErrorScreen.java @@ -8,7 +8,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiMerchant.java b/src/game/java/net/minecraft/client/gui/GuiMerchant.java index ce884f7d..1b03052e 100755 --- a/src/game/java/net/minecraft/client/gui/GuiMerchant.java +++ b/src/game/java/net/minecraft/client/gui/GuiMerchant.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiMultiplayer.java b/src/game/java/net/minecraft/client/gui/GuiMultiplayer.java index d5aeab11..08de930a 100755 --- a/src/game/java/net/minecraft/client/gui/GuiMultiplayer.java +++ b/src/game/java/net/minecraft/client/gui/GuiMultiplayer.java @@ -33,7 +33,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiNewChat.java b/src/game/java/net/minecraft/client/gui/GuiNewChat.java index 5047cfa6..fc0a47f0 100755 --- a/src/game/java/net/minecraft/client/gui/GuiNewChat.java +++ b/src/game/java/net/minecraft/client/gui/GuiNewChat.java @@ -20,7 +20,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiOptionButton.java b/src/game/java/net/minecraft/client/gui/GuiOptionButton.java index 3ea9cbec..3f198fd8 100755 --- a/src/game/java/net/minecraft/client/gui/GuiOptionButton.java +++ b/src/game/java/net/minecraft/client/gui/GuiOptionButton.java @@ -8,7 +8,7 @@ import net.minecraft.client.settings.GameSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiOptionSlider.java b/src/game/java/net/minecraft/client/gui/GuiOptionSlider.java index 0c97f190..00f72699 100755 --- a/src/game/java/net/minecraft/client/gui/GuiOptionSlider.java +++ b/src/game/java/net/minecraft/client/gui/GuiOptionSlider.java @@ -11,7 +11,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiOptions.java b/src/game/java/net/minecraft/client/gui/GuiOptions.java index fdae3805..41c339cc 100755 --- a/src/game/java/net/minecraft/client/gui/GuiOptions.java +++ b/src/game/java/net/minecraft/client/gui/GuiOptions.java @@ -34,7 +34,7 @@ import net.minecraft.world.EnumDifficulty; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiOptionsRowList.java b/src/game/java/net/minecraft/client/gui/GuiOptionsRowList.java index 3c674cfd..086fff94 100755 --- a/src/game/java/net/minecraft/client/gui/GuiOptionsRowList.java +++ b/src/game/java/net/minecraft/client/gui/GuiOptionsRowList.java @@ -14,7 +14,7 @@ import net.minecraft.client.settings.GameSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiOverlayDebug.java b/src/game/java/net/minecraft/client/gui/GuiOverlayDebug.java index c06a90bc..0ac88554 100755 --- a/src/game/java/net/minecraft/client/gui/GuiOverlayDebug.java +++ b/src/game/java/net/minecraft/client/gui/GuiOverlayDebug.java @@ -5,7 +5,6 @@ import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; -import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map.Entry; @@ -14,6 +13,7 @@ import org.apache.commons.lang3.StringUtils; import java.util.TimeZone; +import com.carrotsearch.hppc.cursors.ObjectCursor; import com.google.common.base.Strings; import com.google.common.collect.Lists; @@ -50,7 +50,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -169,28 +169,25 @@ public class GuiOverlayDebug extends Gui { this.fontRenderer.drawStringWithShadow(line, x - lw, y - i, 0xFFFFFF); i += 11; - Iterator potions = mc.thePlayer.getActivePotionEffects().iterator(); - if (potions.hasNext()) { - while (potions.hasNext()) { - i += 11; - PotionEffect e = potions.next(); - int t = e.getDuration() / 20; - int m = t / 60; - int s = t % 60; - int j = e.getAmplifier(); - if (j > 0) { - line = I18n.format(e.getEffectName()) - + (j > 0 ? (" " + EnumChatFormatting.YELLOW + EnumChatFormatting.BOLD - + I18n.format("potion.potency." + j) + EnumChatFormatting.RESET) : "") - + " [" + EnumChatFormatting.YELLOW + HString.format("%02d:%02d", m, s) - + EnumChatFormatting.RESET + "]"; - } else { - line = I18n.format(e.getEffectName()) + " [" + EnumChatFormatting.YELLOW - + HString.format("%02d:%02d", m, s) + EnumChatFormatting.RESET + "]"; - } - lw = fontRenderer.getStringWidth(line); - this.fontRenderer.drawStringWithShadow(line, x - lw, y - i, 0xFFFFFF); + for (ObjectCursor ee : mc.thePlayer.getActivePotionEffects()) { + i += 11; + PotionEffect e = ee.value; + int t = e.getDuration() / 20; + int m = t / 60; + int s = t % 60; + int j = e.getAmplifier(); + if (j > 0) { + line = I18n.format(e.getEffectName()) + + (j > 0 ? (" " + EnumChatFormatting.YELLOW + EnumChatFormatting.BOLD + + I18n.format("potion.potency." + j) + EnumChatFormatting.RESET) : "") + + " [" + EnumChatFormatting.YELLOW + HString.format("%02d:%02d", m, s) + + EnumChatFormatting.RESET + "]"; + } else { + line = I18n.format(e.getEffectName()) + " [" + EnumChatFormatting.YELLOW + + HString.format("%02d:%02d", m, s) + EnumChatFormatting.RESET + "]"; } + lw = fontRenderer.getStringWidth(line); + this.fontRenderer.drawStringWithShadow(line, x - lw, y - i, 0xFFFFFF); } } @@ -435,7 +432,7 @@ public class GuiOverlayDebug extends Gui { long j = EagRuntime.totalMemory(); long k = EagRuntime.freeMemory(); long l = j - k; - arraylist = Lists.newArrayList(new String[] { + arraylist = Lists.newArrayList(new String[] { "Platform: Desktop", HString.format("Java: %s %dbit", new Object[] { System.getProperty("java.version"), Integer.valueOf(this.mc.isJava64bit() ? 64 : 32) }), @@ -450,12 +447,12 @@ public class GuiOverlayDebug extends Gui { EaglercraftGPU.glGetString(7936) }), EaglercraftGPU.glGetString(7937), EaglercraftGPU.glGetString(7938) }); } else { - arraylist = Lists.newArrayList( - new String[] { "Java: TeaVM", "", HString.format("CPU: %s", new Object[] { "eaglercraft" }), "", - HString.format("Display: %dx%d (%s)", - new Object[] { Integer.valueOf(Display.getWidth()), - Integer.valueOf(Display.getHeight()), EaglercraftGPU.glGetString(7936) }), - EaglercraftGPU.glGetString(7937), EaglercraftGPU.glGetString(7938) }); + arraylist = Lists.newArrayList(new String[] { "Platform: " + EagRuntime.getPlatformType().getName(), + "Java: TeaVM", "", HString.format("CPU: %s", new Object[] { "eaglercraft" }), "", + HString.format("Display: %dx%d (%s)", + new Object[] { Integer.valueOf(Display.getWidth()), Integer.valueOf(Display.getHeight()), + EaglercraftGPU.glGetString(7936) }), + EaglercraftGPU.glGetString(7937), EaglercraftGPU.glGetString(7938) }); } if (this.isReducedDebug()) { return arraylist; diff --git a/src/game/java/net/minecraft/client/gui/GuiPageButtonList.java b/src/game/java/net/minecraft/client/gui/GuiPageButtonList.java index 68c937a8..82fbf667 100755 --- a/src/game/java/net/minecraft/client/gui/GuiPageButtonList.java +++ b/src/game/java/net/minecraft/client/gui/GuiPageButtonList.java @@ -2,6 +2,8 @@ package net.minecraft.client.gui; import java.util.List; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import com.google.common.base.Objects; import com.google.common.base.Predicate; import com.google.common.base.Predicates; @@ -10,7 +12,6 @@ import com.google.common.collect.Lists; import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction; import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent; import net.minecraft.client.Minecraft; -import net.minecraft.util.IntHashMap; /**+ * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. @@ -18,7 +19,7 @@ import net.minecraft.util.IntHashMap; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -34,7 +35,7 @@ import net.minecraft.util.IntHashMap; */ public class GuiPageButtonList extends GuiListExtended { private final List field_178074_u = Lists.newArrayList(); - private final IntHashMap field_178073_v = new IntHashMap(); + private final IntObjectMap field_178073_v = new IntObjectHashMap<>(); private final List field_178072_w = Lists.newArrayList(); private final GuiPageButtonList.GuiListEntry[][] field_178078_x; private int field_178077_y; @@ -65,14 +66,14 @@ public class GuiPageButtonList extends GuiListExtended { GuiPageButtonList.GuiEntry guipagebuttonlist$guientry = new GuiPageButtonList.GuiEntry(gui, gui1); this.field_178074_u.add(guipagebuttonlist$guientry); if (guipagebuttonlist$guilistentry != null && gui != null) { - this.field_178073_v.addKey(guipagebuttonlist$guilistentry.func_178935_b(), gui); + this.field_178073_v.put(guipagebuttonlist$guilistentry.func_178935_b(), gui); if (gui instanceof GuiTextField) { this.field_178072_w.add((GuiTextField) gui); } } if (guipagebuttonlist$guilistentry1 != null && gui1 != null) { - this.field_178073_v.addKey(guipagebuttonlist$guilistentry1.func_178935_b(), gui1); + this.field_178073_v.put(guipagebuttonlist$guilistentry1.func_178935_b(), gui1); if (gui1 instanceof GuiTextField) { this.field_178072_w.add((GuiTextField) gui1); } @@ -89,9 +90,9 @@ public class GuiPageButtonList extends GuiListExtended { GuiPageButtonList.GuiListEntry guipagebuttonlist$guilistentry = this.field_178078_x[this.field_178077_y][i]; GuiPageButtonList.GuiListEntry guipagebuttonlist$guilistentry1 = i < this.field_178078_x[this.field_178077_y].length - 1 ? this.field_178078_x[this.field_178077_y][i + 1] : null; - Gui gui = (Gui) this.field_178073_v.lookup(guipagebuttonlist$guilistentry.func_178935_b()); + Gui gui = this.field_178073_v.get(guipagebuttonlist$guilistentry.func_178935_b()); Gui gui1 = guipagebuttonlist$guilistentry1 != null - ? (Gui) this.field_178073_v.lookup(guipagebuttonlist$guilistentry1.func_178935_b()) + ? this.field_178073_v.get(guipagebuttonlist$guilistentry1.func_178935_b()) : null; GuiPageButtonList.GuiEntry guipagebuttonlist$guientry = new GuiPageButtonList.GuiEntry(gui, gui1); this.field_178074_u.add(guipagebuttonlist$guientry); @@ -136,7 +137,7 @@ public class GuiPageButtonList extends GuiListExtended { } public Gui func_178061_c(int parInt1) { - return (Gui) this.field_178073_v.lookup(parInt1); + return this.field_178073_v.get(parInt1); } private void func_178060_e(int parInt1, int parInt2) { @@ -144,14 +145,14 @@ public class GuiPageButtonList extends GuiListExtended { GuiListEntry[] etr = this.field_178078_x[parInt1]; for (int i = 0; i < etr.length; ++i) { if (etr[i] != null) { - this.func_178066_a((Gui) this.field_178073_v.lookup(etr[i].func_178935_b()), false); + this.func_178066_a(this.field_178073_v.get(etr[i].func_178935_b()), false); } } etr = this.field_178078_x[parInt2]; for (int i = 0; i < etr.length; ++i) { if (etr[i] != null) { - this.func_178066_a((Gui) this.field_178073_v.lookup(etr[i].func_178935_b()), true); + this.func_178066_a(this.field_178073_v.get(etr[i].func_178935_b()), true); } } diff --git a/src/game/java/net/minecraft/client/gui/GuiPlayerTabOverlay.java b/src/game/java/net/minecraft/client/gui/GuiPlayerTabOverlay.java index 7233bb3d..8318ffb7 100755 --- a/src/game/java/net/minecraft/client/gui/GuiPlayerTabOverlay.java +++ b/src/game/java/net/minecraft/client/gui/GuiPlayerTabOverlay.java @@ -30,7 +30,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiRenameWorld.java b/src/game/java/net/minecraft/client/gui/GuiRenameWorld.java index 7322d165..f6d1c769 100755 --- a/src/game/java/net/minecraft/client/gui/GuiRenameWorld.java +++ b/src/game/java/net/minecraft/client/gui/GuiRenameWorld.java @@ -14,7 +14,7 @@ import net.minecraft.world.storage.WorldInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiRepair.java b/src/game/java/net/minecraft/client/gui/GuiRepair.java index 9167e7c1..310dd47a 100755 --- a/src/game/java/net/minecraft/client/gui/GuiRepair.java +++ b/src/game/java/net/minecraft/client/gui/GuiRepair.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiResourcePackAvailable.java b/src/game/java/net/minecraft/client/gui/GuiResourcePackAvailable.java index 9ccf60e4..e705c5df 100755 --- a/src/game/java/net/minecraft/client/gui/GuiResourcePackAvailable.java +++ b/src/game/java/net/minecraft/client/gui/GuiResourcePackAvailable.java @@ -12,7 +12,7 @@ import net.minecraft.client.resources.ResourcePackListEntry; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiResourcePackList.java b/src/game/java/net/minecraft/client/gui/GuiResourcePackList.java index cb61085a..843c87ac 100755 --- a/src/game/java/net/minecraft/client/gui/GuiResourcePackList.java +++ b/src/game/java/net/minecraft/client/gui/GuiResourcePackList.java @@ -13,7 +13,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiResourcePackSelected.java b/src/game/java/net/minecraft/client/gui/GuiResourcePackSelected.java index c6f597ec..f9b00918 100755 --- a/src/game/java/net/minecraft/client/gui/GuiResourcePackSelected.java +++ b/src/game/java/net/minecraft/client/gui/GuiResourcePackSelected.java @@ -12,7 +12,7 @@ import net.minecraft.client.resources.ResourcePackListEntry; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiScreen.java b/src/game/java/net/minecraft/client/gui/GuiScreen.java index cb628b88..ac89da4b 100755 --- a/src/game/java/net/minecraft/client/gui/GuiScreen.java +++ b/src/game/java/net/minecraft/client/gui/GuiScreen.java @@ -5,14 +5,14 @@ import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Set; import net.lax1dude.eaglercraft.v1_8.internal.EnumTouchEvent; import org.apache.commons.lang3.StringUtils; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import com.google.common.base.Splitter; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -60,7 +60,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -574,7 +574,7 @@ public abstract class GuiScreen extends Gui implements GuiYesNoCallback { } - public final Map touchStarts = new HashMap<>(); + public final IntObjectMap touchStarts = new IntObjectHashMap<>(); /** * Handles touch input. diff --git a/src/game/java/net/minecraft/client/gui/GuiScreenAddServer.java b/src/game/java/net/minecraft/client/gui/GuiScreenAddServer.java index 91731f51..6474d3e4 100755 --- a/src/game/java/net/minecraft/client/gui/GuiScreenAddServer.java +++ b/src/game/java/net/minecraft/client/gui/GuiScreenAddServer.java @@ -12,7 +12,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiScreenBook.java b/src/game/java/net/minecraft/client/gui/GuiScreenBook.java index 1683573b..429048a6 100755 --- a/src/game/java/net/minecraft/client/gui/GuiScreenBook.java +++ b/src/game/java/net/minecraft/client/gui/GuiScreenBook.java @@ -36,7 +36,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiScreenCustomizePresets.java b/src/game/java/net/minecraft/client/gui/GuiScreenCustomizePresets.java index 76f9eabc..fb45ab7d 100755 --- a/src/game/java/net/minecraft/client/gui/GuiScreenCustomizePresets.java +++ b/src/game/java/net/minecraft/client/gui/GuiScreenCustomizePresets.java @@ -20,7 +20,7 @@ import net.minecraft.world.gen.ChunkProviderSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiScreenOptionsSounds.java b/src/game/java/net/minecraft/client/gui/GuiScreenOptionsSounds.java index 84e12d5c..2376a160 100755 --- a/src/game/java/net/minecraft/client/gui/GuiScreenOptionsSounds.java +++ b/src/game/java/net/minecraft/client/gui/GuiScreenOptionsSounds.java @@ -16,7 +16,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiScreenResourcePacks.java b/src/game/java/net/minecraft/client/gui/GuiScreenResourcePacks.java index 1210ab67..d4bb96e2 100755 --- a/src/game/java/net/minecraft/client/gui/GuiScreenResourcePacks.java +++ b/src/game/java/net/minecraft/client/gui/GuiScreenResourcePacks.java @@ -25,7 +25,7 @@ import net.minecraft.client.resources.ResourcePackRepository; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiScreenServerList.java b/src/game/java/net/minecraft/client/gui/GuiScreenServerList.java index 57932985..2673291c 100755 --- a/src/game/java/net/minecraft/client/gui/GuiScreenServerList.java +++ b/src/game/java/net/minecraft/client/gui/GuiScreenServerList.java @@ -12,7 +12,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiScreenWorking.java b/src/game/java/net/minecraft/client/gui/GuiScreenWorking.java index ff72f19b..9508f840 100755 --- a/src/game/java/net/minecraft/client/gui/GuiScreenWorking.java +++ b/src/game/java/net/minecraft/client/gui/GuiScreenWorking.java @@ -8,7 +8,7 @@ import net.minecraft.util.IProgressUpdate; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiSelectWorld.java b/src/game/java/net/minecraft/client/gui/GuiSelectWorld.java index 86860c37..038d8620 100755 --- a/src/game/java/net/minecraft/client/gui/GuiSelectWorld.java +++ b/src/game/java/net/minecraft/client/gui/GuiSelectWorld.java @@ -38,7 +38,7 @@ import net.lax1dude.eaglercraft.v1_8.sp.gui.GuiScreenLANInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiSleepMP.java b/src/game/java/net/minecraft/client/gui/GuiSleepMP.java index 0637b535..f8f81484 100755 --- a/src/game/java/net/minecraft/client/gui/GuiSleepMP.java +++ b/src/game/java/net/minecraft/client/gui/GuiSleepMP.java @@ -10,7 +10,7 @@ import net.minecraft.network.play.client.C0BPacketEntityAction; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiSlider.java b/src/game/java/net/minecraft/client/gui/GuiSlider.java index 6f9b26f8..de8625ce 100755 --- a/src/game/java/net/minecraft/client/gui/GuiSlider.java +++ b/src/game/java/net/minecraft/client/gui/GuiSlider.java @@ -10,7 +10,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiSlot.java b/src/game/java/net/minecraft/client/gui/GuiSlot.java index 895f440d..bacc4672 100755 --- a/src/game/java/net/minecraft/client/gui/GuiSlot.java +++ b/src/game/java/net/minecraft/client/gui/GuiSlot.java @@ -22,7 +22,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiSpectator.java b/src/game/java/net/minecraft/client/gui/GuiSpectator.java index 38acffc9..a23e7cfb 100755 --- a/src/game/java/net/minecraft/client/gui/GuiSpectator.java +++ b/src/game/java/net/minecraft/client/gui/GuiSpectator.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiTextField.java b/src/game/java/net/minecraft/client/gui/GuiTextField.java index c691ff14..d6f64278 100755 --- a/src/game/java/net/minecraft/client/gui/GuiTextField.java +++ b/src/game/java/net/minecraft/client/gui/GuiTextField.java @@ -19,7 +19,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiUtilRenderComponents.java b/src/game/java/net/minecraft/client/gui/GuiUtilRenderComponents.java index 245af26a..7cf6c8e1 100755 --- a/src/game/java/net/minecraft/client/gui/GuiUtilRenderComponents.java +++ b/src/game/java/net/minecraft/client/gui/GuiUtilRenderComponents.java @@ -16,7 +16,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiVideoSettings.java b/src/game/java/net/minecraft/client/gui/GuiVideoSettings.java index 28688e8f..246f47b4 100755 --- a/src/game/java/net/minecraft/client/gui/GuiVideoSettings.java +++ b/src/game/java/net/minecraft/client/gui/GuiVideoSettings.java @@ -16,7 +16,7 @@ import net.minecraft.client.settings.GameSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiWinGame.java b/src/game/java/net/minecraft/client/gui/GuiWinGame.java index acc158d1..e8cad44a 100755 --- a/src/game/java/net/minecraft/client/gui/GuiWinGame.java +++ b/src/game/java/net/minecraft/client/gui/GuiWinGame.java @@ -30,7 +30,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiYesNo.java b/src/game/java/net/minecraft/client/gui/GuiYesNo.java index 4d061b05..2ee521c6 100755 --- a/src/game/java/net/minecraft/client/gui/GuiYesNo.java +++ b/src/game/java/net/minecraft/client/gui/GuiYesNo.java @@ -12,7 +12,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/GuiYesNoCallback.java b/src/game/java/net/minecraft/client/gui/GuiYesNoCallback.java index 9078709b..26500b45 100755 --- a/src/game/java/net/minecraft/client/gui/GuiYesNoCallback.java +++ b/src/game/java/net/minecraft/client/gui/GuiYesNoCallback.java @@ -6,7 +6,7 @@ package net.minecraft.client.gui; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/IProgressMeter.java b/src/game/java/net/minecraft/client/gui/IProgressMeter.java index 71b3c73d..10cad525 100755 --- a/src/game/java/net/minecraft/client/gui/IProgressMeter.java +++ b/src/game/java/net/minecraft/client/gui/IProgressMeter.java @@ -6,7 +6,7 @@ package net.minecraft.client.gui; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/MapItemRenderer.java b/src/game/java/net/minecraft/client/gui/MapItemRenderer.java index d70f8245..e8e3ac82 100755 --- a/src/game/java/net/minecraft/client/gui/MapItemRenderer.java +++ b/src/game/java/net/minecraft/client/gui/MapItemRenderer.java @@ -23,7 +23,7 @@ import net.minecraft.world.storage.MapData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/ScaledResolution.java b/src/game/java/net/minecraft/client/gui/ScaledResolution.java index 0fd6bacd..709de89d 100755 --- a/src/game/java/net/minecraft/client/gui/ScaledResolution.java +++ b/src/game/java/net/minecraft/client/gui/ScaledResolution.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/ScreenChatOptions.java b/src/game/java/net/minecraft/client/gui/ScreenChatOptions.java index 687c959d..c7b4494a 100755 --- a/src/game/java/net/minecraft/client/gui/ScreenChatOptions.java +++ b/src/game/java/net/minecraft/client/gui/ScreenChatOptions.java @@ -10,7 +10,7 @@ import net.minecraft.client.settings.GameSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/ServerListEntryNormal.java b/src/game/java/net/minecraft/client/gui/ServerListEntryNormal.java index 68cacb10..9e0f9737 100755 --- a/src/game/java/net/minecraft/client/gui/ServerListEntryNormal.java +++ b/src/game/java/net/minecraft/client/gui/ServerListEntryNormal.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/ServerSelectionList.java b/src/game/java/net/minecraft/client/gui/ServerSelectionList.java index 4f834aba..8789ce82 100755 --- a/src/game/java/net/minecraft/client/gui/ServerSelectionList.java +++ b/src/game/java/net/minecraft/client/gui/ServerSelectionList.java @@ -17,7 +17,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/achievement/GuiAchievement.java b/src/game/java/net/minecraft/client/gui/achievement/GuiAchievement.java index 39e43df1..512f7e3c 100755 --- a/src/game/java/net/minecraft/client/gui/achievement/GuiAchievement.java +++ b/src/game/java/net/minecraft/client/gui/achievement/GuiAchievement.java @@ -18,7 +18,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/achievement/GuiAchievements.java b/src/game/java/net/minecraft/client/gui/achievement/GuiAchievements.java index 68cbfbb2..a1984d3d 100755 --- a/src/game/java/net/minecraft/client/gui/achievement/GuiAchievements.java +++ b/src/game/java/net/minecraft/client/gui/achievement/GuiAchievements.java @@ -32,7 +32,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/achievement/GuiStats.java b/src/game/java/net/minecraft/client/gui/achievement/GuiStats.java index 1927e5b5..4fa23861 100755 --- a/src/game/java/net/minecraft/client/gui/achievement/GuiStats.java +++ b/src/game/java/net/minecraft/client/gui/achievement/GuiStats.java @@ -5,6 +5,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; +import com.carrotsearch.hppc.cursors.ObjectCursor; import com.google.common.collect.Lists; import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction; @@ -36,7 +37,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -665,7 +666,8 @@ public class GuiStats extends GuiScreen implements IProgressMeter { GuiStats.this.fontRendererObj.FONT_HEIGHT * 4); this.setShowSelectionBox(false); - for (EntityList.EntityEggInfo entitylist$entityegginfo : EntityList.entityEggs.values()) { + for (ObjectCursor entitylist$entityegginfo_ : EntityList.entityEggs.values()) { + EntityList.EntityEggInfo entitylist$entityegginfo = entitylist$entityegginfo_.value; if (GuiStats.this.field_146546_t.readStat(entitylist$entityegginfo.field_151512_d) > 0 || GuiStats.this.field_146546_t.readStat(entitylist$entityegginfo.field_151513_e) > 0) { this.field_148222_l.add(entitylist$entityegginfo); diff --git a/src/game/java/net/minecraft/client/gui/inventory/CreativeCrafting.java b/src/game/java/net/minecraft/client/gui/inventory/CreativeCrafting.java index c49f60ca..679472e6 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/CreativeCrafting.java +++ b/src/game/java/net/minecraft/client/gui/inventory/CreativeCrafting.java @@ -14,7 +14,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiBeacon.java b/src/game/java/net/minecraft/client/gui/inventory/GuiBeacon.java index 309a3133..1f2c09c6 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiBeacon.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiBeacon.java @@ -28,7 +28,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiBrewingStand.java b/src/game/java/net/minecraft/client/gui/inventory/GuiBrewingStand.java index def2bf84..e93933fb 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiBrewingStand.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiBrewingStand.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiChest.java b/src/game/java/net/minecraft/client/gui/inventory/GuiChest.java index dfffcb58..8284b328 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiChest.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiChest.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiContainer.java b/src/game/java/net/minecraft/client/gui/inventory/GuiContainer.java index 681f4c43..0142aba0 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiContainer.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiContainer.java @@ -29,7 +29,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiContainerCreative.java b/src/game/java/net/minecraft/client/gui/inventory/GuiContainerCreative.java index 7aeb4517..4af8a5d0 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiContainerCreative.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiContainerCreative.java @@ -3,8 +3,8 @@ package net.minecraft.client.gui.inventory; import java.io.IOException; import java.util.Iterator; import java.util.List; -import java.util.Map; +import com.carrotsearch.hppc.IntIntMap; import com.google.common.collect.Lists; import net.lax1dude.eaglercraft.v1_8.Keyboard; @@ -43,7 +43,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -564,10 +564,9 @@ public class GuiContainerCreative extends InventoryEffectRenderer { this.mc.gameSettings.advancedItemTooltips); CreativeTabs creativetabs = itemstack.getItem().getCreativeTab(); if (creativetabs == null && itemstack.getItem() == Items.enchanted_book) { - Map map = EnchantmentHelper.getEnchantments(itemstack); + IntIntMap map = EnchantmentHelper.getEnchantments(itemstack); if (map.size() == 1) { - Enchantment enchantment = Enchantment - .getEnchantmentById(((Integer) map.keySet().iterator().next()).intValue()); + Enchantment enchantment = Enchantment.getEnchantmentById(map.keys().iterator().next().value); for (int m = 0; m < CreativeTabs.creativeTabArray.length; ++m) { CreativeTabs creativetabs1 = CreativeTabs.creativeTabArray[m]; diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiCrafting.java b/src/game/java/net/minecraft/client/gui/inventory/GuiCrafting.java index 8dd7603a..36e27a48 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiCrafting.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiCrafting.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiDispenser.java b/src/game/java/net/minecraft/client/gui/inventory/GuiDispenser.java index 0370dd22..6ebee973 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiDispenser.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiDispenser.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiEditSign.java b/src/game/java/net/minecraft/client/gui/inventory/GuiEditSign.java index 9d48a8dc..5faed6c0 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiEditSign.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiEditSign.java @@ -24,7 +24,7 @@ import net.minecraft.util.ChatComponentText; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiFurnace.java b/src/game/java/net/minecraft/client/gui/inventory/GuiFurnace.java index de63db78..a8cdaf47 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiFurnace.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiFurnace.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiInventory.java b/src/game/java/net/minecraft/client/gui/inventory/GuiInventory.java index 50a23211..3e65ad32 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiInventory.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiInventory.java @@ -19,7 +19,7 @@ import net.minecraft.entity.player.EntityPlayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiScreenHorseInventory.java b/src/game/java/net/minecraft/client/gui/inventory/GuiScreenHorseInventory.java index 4f9410f2..c6de4586 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiScreenHorseInventory.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiScreenHorseInventory.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/spectator/BaseSpectatorGroup.java b/src/game/java/net/minecraft/client/gui/spectator/BaseSpectatorGroup.java index f4652f5a..c226ed43 100755 --- a/src/game/java/net/minecraft/client/gui/spectator/BaseSpectatorGroup.java +++ b/src/game/java/net/minecraft/client/gui/spectator/BaseSpectatorGroup.java @@ -15,7 +15,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuObject.java b/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuObject.java index d7141f40..75a402bf 100755 --- a/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuObject.java +++ b/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuObject.java @@ -8,7 +8,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuRecipient.java b/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuRecipient.java index 60ea26b9..08800104 100755 --- a/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuRecipient.java +++ b/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuRecipient.java @@ -6,7 +6,7 @@ package net.minecraft.client.gui.spectator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuView.java b/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuView.java index f90dc0d7..1b27baa1 100755 --- a/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuView.java +++ b/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuView.java @@ -10,7 +10,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/spectator/PlayerMenuObject.java b/src/game/java/net/minecraft/client/gui/spectator/PlayerMenuObject.java index f1003e53..583d5bdd 100755 --- a/src/game/java/net/minecraft/client/gui/spectator/PlayerMenuObject.java +++ b/src/game/java/net/minecraft/client/gui/spectator/PlayerMenuObject.java @@ -14,7 +14,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/spectator/SpectatorMenu.java b/src/game/java/net/minecraft/client/gui/spectator/SpectatorMenu.java index 80dc37f8..80eb9ea0 100755 --- a/src/game/java/net/minecraft/client/gui/spectator/SpectatorMenu.java +++ b/src/game/java/net/minecraft/client/gui/spectator/SpectatorMenu.java @@ -19,7 +19,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/spectator/categories/SpectatorDetails.java b/src/game/java/net/minecraft/client/gui/spectator/categories/SpectatorDetails.java index 8bbd8c94..b9341a4f 100755 --- a/src/game/java/net/minecraft/client/gui/spectator/categories/SpectatorDetails.java +++ b/src/game/java/net/minecraft/client/gui/spectator/categories/SpectatorDetails.java @@ -14,7 +14,7 @@ import net.minecraft.client.gui.spectator.SpectatorMenu; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/spectator/categories/TeleportToPlayer.java b/src/game/java/net/minecraft/client/gui/spectator/categories/TeleportToPlayer.java index 4e39cef8..5382040d 100755 --- a/src/game/java/net/minecraft/client/gui/spectator/categories/TeleportToPlayer.java +++ b/src/game/java/net/minecraft/client/gui/spectator/categories/TeleportToPlayer.java @@ -26,7 +26,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/gui/spectator/categories/TeleportToTeam.java b/src/game/java/net/minecraft/client/gui/spectator/categories/TeleportToTeam.java index 80e38085..d4e6af39 100755 --- a/src/game/java/net/minecraft/client/gui/spectator/categories/TeleportToTeam.java +++ b/src/game/java/net/minecraft/client/gui/spectator/categories/TeleportToTeam.java @@ -25,7 +25,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/main/GameConfiguration.java b/src/game/java/net/minecraft/client/main/GameConfiguration.java index 53ee71d3..13569349 100755 --- a/src/game/java/net/minecraft/client/main/GameConfiguration.java +++ b/src/game/java/net/minecraft/client/main/GameConfiguration.java @@ -8,7 +8,7 @@ import net.minecraft.util.Session; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/main/Main.java b/src/game/java/net/minecraft/client/main/Main.java index a38e704e..8fce2430 100755 --- a/src/game/java/net/minecraft/client/main/Main.java +++ b/src/game/java/net/minecraft/client/main/Main.java @@ -10,7 +10,7 @@ import net.minecraft.util.Session; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelArmorStand.java b/src/game/java/net/minecraft/client/model/ModelArmorStand.java index d2a0cc68..bfb6444d 100755 --- a/src/game/java/net/minecraft/client/model/ModelArmorStand.java +++ b/src/game/java/net/minecraft/client/model/ModelArmorStand.java @@ -10,7 +10,7 @@ import net.minecraft.entity.item.EntityArmorStand; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelArmorStandArmor.java b/src/game/java/net/minecraft/client/model/ModelArmorStandArmor.java index c5b9d3ec..a36e9b43 100755 --- a/src/game/java/net/minecraft/client/model/ModelArmorStandArmor.java +++ b/src/game/java/net/minecraft/client/model/ModelArmorStandArmor.java @@ -9,7 +9,7 @@ import net.minecraft.entity.item.EntityArmorStand; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelBanner.java b/src/game/java/net/minecraft/client/model/ModelBanner.java index d17fcd99..425abb06 100755 --- a/src/game/java/net/minecraft/client/model/ModelBanner.java +++ b/src/game/java/net/minecraft/client/model/ModelBanner.java @@ -6,7 +6,7 @@ package net.minecraft.client.model; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelBase.java b/src/game/java/net/minecraft/client/model/ModelBase.java index 61473a1a..76b14c90 100755 --- a/src/game/java/net/minecraft/client/model/ModelBase.java +++ b/src/game/java/net/minecraft/client/model/ModelBase.java @@ -16,7 +16,7 @@ import net.minecraft.entity.EntityLivingBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelBat.java b/src/game/java/net/minecraft/client/model/ModelBat.java index 031513bd..42da2010 100755 --- a/src/game/java/net/minecraft/client/model/ModelBat.java +++ b/src/game/java/net/minecraft/client/model/ModelBat.java @@ -10,7 +10,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelBiped.java b/src/game/java/net/minecraft/client/model/ModelBiped.java index b3003e0c..53c9de8f 100755 --- a/src/game/java/net/minecraft/client/model/ModelBiped.java +++ b/src/game/java/net/minecraft/client/model/ModelBiped.java @@ -10,7 +10,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelBlaze.java b/src/game/java/net/minecraft/client/model/ModelBlaze.java index 172b0adc..1e6a919d 100755 --- a/src/game/java/net/minecraft/client/model/ModelBlaze.java +++ b/src/game/java/net/minecraft/client/model/ModelBlaze.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelBoat.java b/src/game/java/net/minecraft/client/model/ModelBoat.java index f0c65508..9a5c59a8 100755 --- a/src/game/java/net/minecraft/client/model/ModelBoat.java +++ b/src/game/java/net/minecraft/client/model/ModelBoat.java @@ -8,7 +8,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelBook.java b/src/game/java/net/minecraft/client/model/ModelBook.java index 3b56158b..86e5d92a 100755 --- a/src/game/java/net/minecraft/client/model/ModelBook.java +++ b/src/game/java/net/minecraft/client/model/ModelBook.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelBox.java b/src/game/java/net/minecraft/client/model/ModelBox.java index 903ccd02..ea7d9875 100755 --- a/src/game/java/net/minecraft/client/model/ModelBox.java +++ b/src/game/java/net/minecraft/client/model/ModelBox.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelChest.java b/src/game/java/net/minecraft/client/model/ModelChest.java index 42d3662d..e617fe40 100755 --- a/src/game/java/net/minecraft/client/model/ModelChest.java +++ b/src/game/java/net/minecraft/client/model/ModelChest.java @@ -6,7 +6,7 @@ package net.minecraft.client.model; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelChicken.java b/src/game/java/net/minecraft/client/model/ModelChicken.java index a564ae22..06daa9e8 100755 --- a/src/game/java/net/minecraft/client/model/ModelChicken.java +++ b/src/game/java/net/minecraft/client/model/ModelChicken.java @@ -10,7 +10,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelCow.java b/src/game/java/net/minecraft/client/model/ModelCow.java index 281d9b11..efa6a65c 100755 --- a/src/game/java/net/minecraft/client/model/ModelCow.java +++ b/src/game/java/net/minecraft/client/model/ModelCow.java @@ -6,7 +6,7 @@ package net.minecraft.client.model; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelCreeper.java b/src/game/java/net/minecraft/client/model/ModelCreeper.java index 66cf52d1..cb2108b1 100755 --- a/src/game/java/net/minecraft/client/model/ModelCreeper.java +++ b/src/game/java/net/minecraft/client/model/ModelCreeper.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelDragon.java b/src/game/java/net/minecraft/client/model/ModelDragon.java index 23facaf3..186f8934 100755 --- a/src/game/java/net/minecraft/client/model/ModelDragon.java +++ b/src/game/java/net/minecraft/client/model/ModelDragon.java @@ -14,7 +14,7 @@ import net.minecraft.entity.boss.EntityDragon; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelEnderCrystal.java b/src/game/java/net/minecraft/client/model/ModelEnderCrystal.java index 314e7c1b..cbac9e5c 100755 --- a/src/game/java/net/minecraft/client/model/ModelEnderCrystal.java +++ b/src/game/java/net/minecraft/client/model/ModelEnderCrystal.java @@ -9,7 +9,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelEnderMite.java b/src/game/java/net/minecraft/client/model/ModelEnderMite.java index e04b603c..32c1e77e 100755 --- a/src/game/java/net/minecraft/client/model/ModelEnderMite.java +++ b/src/game/java/net/minecraft/client/model/ModelEnderMite.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelEnderman.java b/src/game/java/net/minecraft/client/model/ModelEnderman.java index 8615635f..ff96feb4 100755 --- a/src/game/java/net/minecraft/client/model/ModelEnderman.java +++ b/src/game/java/net/minecraft/client/model/ModelEnderman.java @@ -8,7 +8,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelGhast.java b/src/game/java/net/minecraft/client/model/ModelGhast.java index 7bbd3794..fb7e418b 100755 --- a/src/game/java/net/minecraft/client/model/ModelGhast.java +++ b/src/game/java/net/minecraft/client/model/ModelGhast.java @@ -12,7 +12,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelGuardian.java b/src/game/java/net/minecraft/client/model/ModelGuardian.java index 33c47c23..c787ae87 100755 --- a/src/game/java/net/minecraft/client/model/ModelGuardian.java +++ b/src/game/java/net/minecraft/client/model/ModelGuardian.java @@ -12,7 +12,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelHorse.java b/src/game/java/net/minecraft/client/model/ModelHorse.java index 6de455d2..aae175eb 100755 --- a/src/game/java/net/minecraft/client/model/ModelHorse.java +++ b/src/game/java/net/minecraft/client/model/ModelHorse.java @@ -12,7 +12,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelHumanoidHead.java b/src/game/java/net/minecraft/client/model/ModelHumanoidHead.java index 1edf6f5d..7025e5b6 100755 --- a/src/game/java/net/minecraft/client/model/ModelHumanoidHead.java +++ b/src/game/java/net/minecraft/client/model/ModelHumanoidHead.java @@ -8,7 +8,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelIronGolem.java b/src/game/java/net/minecraft/client/model/ModelIronGolem.java index 5b0ff19b..99e9814f 100755 --- a/src/game/java/net/minecraft/client/model/ModelIronGolem.java +++ b/src/game/java/net/minecraft/client/model/ModelIronGolem.java @@ -10,7 +10,7 @@ import net.minecraft.entity.monster.EntityIronGolem; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelLargeChest.java b/src/game/java/net/minecraft/client/model/ModelLargeChest.java index 28f7ad88..609e4a6d 100755 --- a/src/game/java/net/minecraft/client/model/ModelLargeChest.java +++ b/src/game/java/net/minecraft/client/model/ModelLargeChest.java @@ -6,7 +6,7 @@ package net.minecraft.client.model; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelLeashKnot.java b/src/game/java/net/minecraft/client/model/ModelLeashKnot.java index 93588791..53216a8a 100755 --- a/src/game/java/net/minecraft/client/model/ModelLeashKnot.java +++ b/src/game/java/net/minecraft/client/model/ModelLeashKnot.java @@ -8,7 +8,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelMagmaCube.java b/src/game/java/net/minecraft/client/model/ModelMagmaCube.java index cf58497c..643b6f04 100755 --- a/src/game/java/net/minecraft/client/model/ModelMagmaCube.java +++ b/src/game/java/net/minecraft/client/model/ModelMagmaCube.java @@ -10,7 +10,7 @@ import net.minecraft.entity.monster.EntityMagmaCube; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelMinecart.java b/src/game/java/net/minecraft/client/model/ModelMinecart.java index 56bc0c6b..e329736f 100755 --- a/src/game/java/net/minecraft/client/model/ModelMinecart.java +++ b/src/game/java/net/minecraft/client/model/ModelMinecart.java @@ -8,7 +8,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelOcelot.java b/src/game/java/net/minecraft/client/model/ModelOcelot.java index 5a61d64d..7243a093 100755 --- a/src/game/java/net/minecraft/client/model/ModelOcelot.java +++ b/src/game/java/net/minecraft/client/model/ModelOcelot.java @@ -12,7 +12,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelPig.java b/src/game/java/net/minecraft/client/model/ModelPig.java index a2bc7636..0e5fab95 100755 --- a/src/game/java/net/minecraft/client/model/ModelPig.java +++ b/src/game/java/net/minecraft/client/model/ModelPig.java @@ -6,7 +6,7 @@ package net.minecraft.client.model; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelPlayer.java b/src/game/java/net/minecraft/client/model/ModelPlayer.java index 05114c18..f9e5ec2a 100755 --- a/src/game/java/net/minecraft/client/model/ModelPlayer.java +++ b/src/game/java/net/minecraft/client/model/ModelPlayer.java @@ -11,7 +11,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelQuadruped.java b/src/game/java/net/minecraft/client/model/ModelQuadruped.java index 4547f03f..51f33377 100755 --- a/src/game/java/net/minecraft/client/model/ModelQuadruped.java +++ b/src/game/java/net/minecraft/client/model/ModelQuadruped.java @@ -10,7 +10,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelRabbit.java b/src/game/java/net/minecraft/client/model/ModelRabbit.java index 60ed61f1..210b954b 100755 --- a/src/game/java/net/minecraft/client/model/ModelRabbit.java +++ b/src/game/java/net/minecraft/client/model/ModelRabbit.java @@ -12,7 +12,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelRenderer.java b/src/game/java/net/minecraft/client/model/ModelRenderer.java index 7f9186fa..6e7ab52f 100755 --- a/src/game/java/net/minecraft/client/model/ModelRenderer.java +++ b/src/game/java/net/minecraft/client/model/ModelRenderer.java @@ -18,7 +18,7 @@ import net.minecraft.client.renderer.Tessellator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelSheep1.java b/src/game/java/net/minecraft/client/model/ModelSheep1.java index b0c7c196..3525f01b 100755 --- a/src/game/java/net/minecraft/client/model/ModelSheep1.java +++ b/src/game/java/net/minecraft/client/model/ModelSheep1.java @@ -10,7 +10,7 @@ import net.minecraft.entity.passive.EntitySheep; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelSheep2.java b/src/game/java/net/minecraft/client/model/ModelSheep2.java index 0cf5f3e1..1fede293 100755 --- a/src/game/java/net/minecraft/client/model/ModelSheep2.java +++ b/src/game/java/net/minecraft/client/model/ModelSheep2.java @@ -10,7 +10,7 @@ import net.minecraft.entity.passive.EntitySheep; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelSign.java b/src/game/java/net/minecraft/client/model/ModelSign.java index e9a0f53e..35404ca5 100755 --- a/src/game/java/net/minecraft/client/model/ModelSign.java +++ b/src/game/java/net/minecraft/client/model/ModelSign.java @@ -6,7 +6,7 @@ package net.minecraft.client.model; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelSilverfish.java b/src/game/java/net/minecraft/client/model/ModelSilverfish.java index fdcd93bc..4c570626 100755 --- a/src/game/java/net/minecraft/client/model/ModelSilverfish.java +++ b/src/game/java/net/minecraft/client/model/ModelSilverfish.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelSkeleton.java b/src/game/java/net/minecraft/client/model/ModelSkeleton.java index 8328e837..89fb98e1 100755 --- a/src/game/java/net/minecraft/client/model/ModelSkeleton.java +++ b/src/game/java/net/minecraft/client/model/ModelSkeleton.java @@ -10,7 +10,7 @@ import net.minecraft.entity.monster.EntitySkeleton; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelSkeletonHead.java b/src/game/java/net/minecraft/client/model/ModelSkeletonHead.java index 6d148bc3..168aa829 100755 --- a/src/game/java/net/minecraft/client/model/ModelSkeletonHead.java +++ b/src/game/java/net/minecraft/client/model/ModelSkeletonHead.java @@ -8,7 +8,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelSlime.java b/src/game/java/net/minecraft/client/model/ModelSlime.java index 85d7e988..6491797b 100755 --- a/src/game/java/net/minecraft/client/model/ModelSlime.java +++ b/src/game/java/net/minecraft/client/model/ModelSlime.java @@ -8,7 +8,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelSnowMan.java b/src/game/java/net/minecraft/client/model/ModelSnowMan.java index c48a88dc..0beacea9 100755 --- a/src/game/java/net/minecraft/client/model/ModelSnowMan.java +++ b/src/game/java/net/minecraft/client/model/ModelSnowMan.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelSpider.java b/src/game/java/net/minecraft/client/model/ModelSpider.java index b4d26dff..c1818628 100755 --- a/src/game/java/net/minecraft/client/model/ModelSpider.java +++ b/src/game/java/net/minecraft/client/model/ModelSpider.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelSquid.java b/src/game/java/net/minecraft/client/model/ModelSquid.java index c6f52fa9..b75480fe 100755 --- a/src/game/java/net/minecraft/client/model/ModelSquid.java +++ b/src/game/java/net/minecraft/client/model/ModelSquid.java @@ -8,7 +8,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelVillager.java b/src/game/java/net/minecraft/client/model/ModelVillager.java index 4c611ef7..4c204433 100755 --- a/src/game/java/net/minecraft/client/model/ModelVillager.java +++ b/src/game/java/net/minecraft/client/model/ModelVillager.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelWitch.java b/src/game/java/net/minecraft/client/model/ModelWitch.java index a2994663..535077be 100755 --- a/src/game/java/net/minecraft/client/model/ModelWitch.java +++ b/src/game/java/net/minecraft/client/model/ModelWitch.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelWither.java b/src/game/java/net/minecraft/client/model/ModelWither.java index 70ad069c..665942b5 100755 --- a/src/game/java/net/minecraft/client/model/ModelWither.java +++ b/src/game/java/net/minecraft/client/model/ModelWither.java @@ -11,7 +11,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelWolf.java b/src/game/java/net/minecraft/client/model/ModelWolf.java index b128317a..979953c4 100755 --- a/src/game/java/net/minecraft/client/model/ModelWolf.java +++ b/src/game/java/net/minecraft/client/model/ModelWolf.java @@ -12,7 +12,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelZombie.java b/src/game/java/net/minecraft/client/model/ModelZombie.java index 05c3dad9..79bd3002 100755 --- a/src/game/java/net/minecraft/client/model/ModelZombie.java +++ b/src/game/java/net/minecraft/client/model/ModelZombie.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/ModelZombieVillager.java b/src/game/java/net/minecraft/client/model/ModelZombieVillager.java index b52017c8..4ae0b981 100755 --- a/src/game/java/net/minecraft/client/model/ModelZombieVillager.java +++ b/src/game/java/net/minecraft/client/model/ModelZombieVillager.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/PositionTextureVertex.java b/src/game/java/net/minecraft/client/model/PositionTextureVertex.java index 290fcbd7..0dcde044 100755 --- a/src/game/java/net/minecraft/client/model/PositionTextureVertex.java +++ b/src/game/java/net/minecraft/client/model/PositionTextureVertex.java @@ -8,7 +8,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/TextureOffset.java b/src/game/java/net/minecraft/client/model/TextureOffset.java index 0882f274..b97dd54e 100755 --- a/src/game/java/net/minecraft/client/model/TextureOffset.java +++ b/src/game/java/net/minecraft/client/model/TextureOffset.java @@ -6,7 +6,7 @@ package net.minecraft.client.model; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/model/TexturedQuad.java b/src/game/java/net/minecraft/client/model/TexturedQuad.java index e9e14203..a2929a44 100755 --- a/src/game/java/net/minecraft/client/model/TexturedQuad.java +++ b/src/game/java/net/minecraft/client/model/TexturedQuad.java @@ -11,7 +11,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/multiplayer/ChunkProviderClient.java b/src/game/java/net/minecraft/client/multiplayer/ChunkProviderClient.java index 32c6e90b..0ce9377b 100755 --- a/src/game/java/net/minecraft/client/multiplayer/ChunkProviderClient.java +++ b/src/game/java/net/minecraft/client/multiplayer/ChunkProviderClient.java @@ -2,6 +2,8 @@ package net.minecraft.client.multiplayer; import java.util.List; +import com.carrotsearch.hppc.LongObjectHashMap; +import com.carrotsearch.hppc.LongObjectMap; import com.google.common.collect.Lists; import net.lax1dude.eaglercraft.v1_8.EagRuntime; @@ -10,7 +12,6 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; import net.minecraft.entity.EnumCreatureType; import net.minecraft.util.BlockPos; import net.minecraft.util.IProgressUpdate; -import net.minecraft.util.LongHashMap; import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.World; import net.minecraft.world.biome.BiomeGenBase; @@ -24,7 +25,7 @@ import net.minecraft.world.chunk.IChunkProvider; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -45,7 +46,7 @@ public class ChunkProviderClient implements IChunkProvider { * The mapping between ChunkCoordinates and Chunks that * ChunkProviderClient maintains. */ - private LongHashMap chunkMapping = new LongHashMap(); + private LongObjectMap chunkMapping = new LongObjectHashMap<>(); /**+ * This may have been intended to be an iterable version of all * currently loaded chunks (MultiplayerChunkCache), with @@ -87,7 +88,7 @@ public class ChunkProviderClient implements IChunkProvider { */ public Chunk loadChunk(int parInt1, int parInt2) { Chunk chunk = new Chunk(this.worldObj, parInt1, parInt2); - this.chunkMapping.add(ChunkCoordIntPair.chunkXZ2Int(parInt1, parInt2), chunk); + this.chunkMapping.put(ChunkCoordIntPair.chunkXZ2Int(parInt1, parInt2), chunk); this.chunkListing.add(chunk); chunk.setChunkLoaded(true); return chunk; @@ -99,7 +100,7 @@ public class ChunkProviderClient implements IChunkProvider { * chunk from the map seed and chunk seed */ public Chunk provideChunk(int i, int j) { - Chunk chunk = (Chunk) this.chunkMapping.getValueByKey(ChunkCoordIntPair.chunkXZ2Int(i, j)); + Chunk chunk = this.chunkMapping.get(ChunkCoordIntPair.chunkXZ2Int(i, j)); return chunk == null ? this.blankChunk : chunk; } @@ -160,7 +161,7 @@ public class ChunkProviderClient implements IChunkProvider { * Converts the instance data to a readable string. */ public String makeString() { - return "MultiplayerChunkCache: " + this.chunkMapping.getNumHashElements() + ", " + this.chunkListing.size(); + return "MultiplayerChunkCache: " + this.chunkMapping.size() + ", " + this.chunkListing.size(); } public List getPossibleCreatures(EnumCreatureType var1, BlockPos var2) { diff --git a/src/game/java/net/minecraft/client/multiplayer/GuiConnecting.java b/src/game/java/net/minecraft/client/multiplayer/GuiConnecting.java index 813c1247..53a0150e 100755 --- a/src/game/java/net/minecraft/client/multiplayer/GuiConnecting.java +++ b/src/game/java/net/minecraft/client/multiplayer/GuiConnecting.java @@ -35,7 +35,7 @@ import net.minecraft.util.ChatComponentText; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/multiplayer/PlayerControllerMP.java b/src/game/java/net/minecraft/client/multiplayer/PlayerControllerMP.java index 73580bfb..223eae8d 100755 --- a/src/game/java/net/minecraft/client/multiplayer/PlayerControllerMP.java +++ b/src/game/java/net/minecraft/client/multiplayer/PlayerControllerMP.java @@ -40,7 +40,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/multiplayer/ServerAddress.java b/src/game/java/net/minecraft/client/multiplayer/ServerAddress.java index e04405cf..acf4b785 100755 --- a/src/game/java/net/minecraft/client/multiplayer/ServerAddress.java +++ b/src/game/java/net/minecraft/client/multiplayer/ServerAddress.java @@ -6,7 +6,7 @@ package net.minecraft.client.multiplayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/multiplayer/ServerData.java b/src/game/java/net/minecraft/client/multiplayer/ServerData.java index 5be03f1f..ade783c4 100755 --- a/src/game/java/net/minecraft/client/multiplayer/ServerData.java +++ b/src/game/java/net/minecraft/client/multiplayer/ServerData.java @@ -23,7 +23,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/multiplayer/ServerList.java b/src/game/java/net/minecraft/client/multiplayer/ServerList.java index 6487e00f..6889ce26 100755 --- a/src/game/java/net/minecraft/client/multiplayer/ServerList.java +++ b/src/game/java/net/minecraft/client/multiplayer/ServerList.java @@ -28,7 +28,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/multiplayer/WorldClient.java b/src/game/java/net/minecraft/client/multiplayer/WorldClient.java index 4eeb770c..377b3f81 100755 --- a/src/game/java/net/minecraft/client/multiplayer/WorldClient.java +++ b/src/game/java/net/minecraft/client/multiplayer/WorldClient.java @@ -4,6 +4,9 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; import java.util.Set; import java.util.concurrent.Callable; +import com.carrotsearch.hppc.LongHashSet; +import com.carrotsearch.hppc.LongSet; +import com.carrotsearch.hppc.cursors.LongCursor; import com.google.common.collect.Sets; import net.minecraft.block.Block; @@ -25,7 +28,6 @@ import net.minecraft.util.BlockPos; import net.minecraft.util.ChatComponentText; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.ResourceLocation; -import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; import net.minecraft.world.WorldProvider; @@ -42,7 +44,7 @@ import net.minecraft.world.storage.WorldInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -72,7 +74,7 @@ public class WorldClient extends World { */ private final Set entitySpawnQueue = Sets.newHashSet(); private final Minecraft mc = Minecraft.getMinecraft(); - private final Set previousActiveChunkSet = Sets.newHashSet(); + private final LongSet previousActiveChunkSet = new LongHashSet(); public WorldClient(NetHandlerPlayClient parNetHandlerPlayClient, WorldSettings parWorldSettings, int parInt1, EnumDifficulty parEnumDifficulty) { @@ -130,20 +132,23 @@ public class WorldClient extends World { protected void updateBlocks() { super.updateBlocks(); - this.previousActiveChunkSet.retainAll(this.activeChunkSet); + this.previousActiveChunkSet.retainAll(this.activeChunkSet::contains); if (this.previousActiveChunkSet.size() == this.activeChunkSet.size()) { this.previousActiveChunkSet.clear(); } int i = 0; - for (ChunkCoordIntPair chunkcoordintpair : this.activeChunkSet) { - if (!this.previousActiveChunkSet.contains(chunkcoordintpair)) { - int j = chunkcoordintpair.chunkXPos * 16; - int k = chunkcoordintpair.chunkZPos * 16; - Chunk chunk = this.getChunkFromChunkCoords(chunkcoordintpair.chunkXPos, chunkcoordintpair.chunkZPos); + for (LongCursor chunkcoordintpair : this.activeChunkSet) { + long l = chunkcoordintpair.value; + if (!this.previousActiveChunkSet.contains(l)) { + int chunkXPos = (int) (l & 4294967295L); + int chunkZPos = (int) (l >>> 32); + int j = chunkXPos * 16; + int k = chunkZPos * 16; + Chunk chunk = this.getChunkFromChunkCoords(chunkXPos, chunkZPos); this.playMoodSoundAndCheckLight(j, k, chunk); - this.previousActiveChunkSet.add(chunkcoordintpair); + this.previousActiveChunkSet.add(l); ++i; if (i >= 10) { return; @@ -229,7 +234,7 @@ public class WorldClient extends World { this.entitySpawnQueue.add(parEntity); } - this.entitiesById.addKey(parInt1, parEntity); + this.entitiesById.put(parInt1, parEntity); } /**+ @@ -237,11 +242,11 @@ public class WorldClient extends World { * exist in this World. */ public Entity getEntityByID(int i) { - return (Entity) (i == this.mc.thePlayer.getEntityId() ? this.mc.thePlayer : super.getEntityByID(i)); + return i == this.mc.thePlayer.getEntityId() ? this.mc.thePlayer : super.getEntityByID(i); } public Entity removeEntityFromWorld(int parInt1) { - Entity entity = (Entity) this.entitiesById.removeObject(parInt1); + Entity entity = this.entitiesById.remove(parInt1); if (entity != null) { this.entityList.remove(entity); this.removeEntity(entity); diff --git a/src/game/java/net/minecraft/client/network/NetHandlerPlayClient.java b/src/game/java/net/minecraft/client/network/NetHandlerPlayClient.java index 3391ffe9..a96a6ae0 100755 --- a/src/game/java/net/minecraft/client/network/NetHandlerPlayClient.java +++ b/src/game/java/net/minecraft/client/network/NetHandlerPlayClient.java @@ -4,12 +4,12 @@ import java.io.IOException; import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import net.lax1dude.eaglercraft.v1_8.ClientUUIDLoadingCache; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import com.carrotsearch.hppc.cursors.ObjectIntCursor; import com.google.common.collect.Maps; import net.lax1dude.eaglercraft.v1_8.netty.Unpooled; @@ -225,7 +225,7 @@ import net.minecraft.world.storage.MapData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -1350,9 +1350,9 @@ public class NetHandlerPlayClient implements INetHandlerPlayClient { public void handleStatistics(S37PacketStatistics packetIn) { boolean flag = false; - for (Entry entry : packetIn.func_148974_c().entrySet()) { - StatBase statbase = (StatBase) entry.getKey(); - int i = ((Integer) entry.getValue()).intValue(); + for (ObjectIntCursor entry : packetIn.func_148974_c()) { + StatBase statbase = entry.key; + int i = entry.value; if (statbase.isAchievement() && i > 0) { if (this.field_147308_k && this.gameController.thePlayer.getStatFileWriter().readStat(statbase) == 0) { Achievement achievement = (Achievement) statbase; diff --git a/src/game/java/net/minecraft/client/network/NetworkPlayerInfo.java b/src/game/java/net/minecraft/client/network/NetworkPlayerInfo.java index 76af28a4..3fc927a7 100755 --- a/src/game/java/net/minecraft/client/network/NetworkPlayerInfo.java +++ b/src/game/java/net/minecraft/client/network/NetworkPlayerInfo.java @@ -16,7 +16,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/Barrier.java b/src/game/java/net/minecraft/client/particle/Barrier.java index 23d6441a..f80f91ff 100755 --- a/src/game/java/net/minecraft/client/particle/Barrier.java +++ b/src/game/java/net/minecraft/client/particle/Barrier.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EffectRenderer.java b/src/game/java/net/minecraft/client/particle/EffectRenderer.java index 66cf1ea1..a22c5081 100755 --- a/src/game/java/net/minecraft/client/particle/EffectRenderer.java +++ b/src/game/java/net/minecraft/client/particle/EffectRenderer.java @@ -4,16 +4,15 @@ import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; import java.util.ArrayList; import java.util.List; -import java.util.Map; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; import net.lax1dude.eaglercraft.v1_8.minecraft.AcceleratedEffectRenderer; import net.lax1dude.eaglercraft.v1_8.minecraft.IAcceleratedParticleEngine; import java.util.concurrent.Callable; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU; import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager; import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer; @@ -44,7 +43,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -70,7 +69,7 @@ public class EffectRenderer { * RNG. */ private EaglercraftRandom rand = new EaglercraftRandom(); - private Map particleTypes = Maps.newHashMap(); + private IntObjectMap particleTypes = new IntObjectHashMap<>(); public static final AcceleratedEffectRenderer vanillaAcceleratedParticleRenderer = new AcceleratedEffectRenderer(); public IAcceleratedParticleEngine acceleratedParticleRenderer = null; @@ -142,7 +141,7 @@ public class EffectRenderer { } public void registerParticle(int id, IParticleFactory particleFactory) { - this.particleTypes.put(Integer.valueOf(id), particleFactory); + this.particleTypes.put(id, particleFactory); } public void emitParticleAtEntity(Entity entityIn, EnumParticleTypes particleTypes) { @@ -154,7 +153,7 @@ public class EffectRenderer { */ public EntityFX spawnEffectParticle(int particleId, double parDouble1, double parDouble2, double parDouble3, double parDouble4, double parDouble5, double parDouble6, int... parArrayOfInt) { - IParticleFactory iparticlefactory = (IParticleFactory) this.particleTypes.get(Integer.valueOf(particleId)); + IParticleFactory iparticlefactory = this.particleTypes.get(particleId); if (iparticlefactory != null) { EntityFX entityfx = iparticlefactory.getEntityFX(particleId, this.worldObj, parDouble1, parDouble2, parDouble3, parDouble4, parDouble5, parDouble6, parArrayOfInt); diff --git a/src/game/java/net/minecraft/client/particle/EntityAuraFX.java b/src/game/java/net/minecraft/client/particle/EntityAuraFX.java index f0d8ee4e..c7a01897 100755 --- a/src/game/java/net/minecraft/client/particle/EntityAuraFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityAuraFX.java @@ -8,7 +8,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityBlockDustFX.java b/src/game/java/net/minecraft/client/particle/EntityBlockDustFX.java index 980c05bd..f2ac74bd 100755 --- a/src/game/java/net/minecraft/client/particle/EntityBlockDustFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityBlockDustFX.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityBreakingFX.java b/src/game/java/net/minecraft/client/particle/EntityBreakingFX.java index 9ccd85b7..56a3dd52 100755 --- a/src/game/java/net/minecraft/client/particle/EntityBreakingFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityBreakingFX.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityBubbleFX.java b/src/game/java/net/minecraft/client/particle/EntityBubbleFX.java index 7da7f7f2..270b8a36 100755 --- a/src/game/java/net/minecraft/client/particle/EntityBubbleFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityBubbleFX.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityCloudFX.java b/src/game/java/net/minecraft/client/particle/EntityCloudFX.java index 45fe1da2..de460929 100755 --- a/src/game/java/net/minecraft/client/particle/EntityCloudFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityCloudFX.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityCrit2FX.java b/src/game/java/net/minecraft/client/particle/EntityCrit2FX.java index 97505ffb..3ec584e8 100755 --- a/src/game/java/net/minecraft/client/particle/EntityCrit2FX.java +++ b/src/game/java/net/minecraft/client/particle/EntityCrit2FX.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityCritFX.java b/src/game/java/net/minecraft/client/particle/EntityCritFX.java index c4a3032f..d91c8a1c 100755 --- a/src/game/java/net/minecraft/client/particle/EntityCritFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityCritFX.java @@ -8,7 +8,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityDiggingFX.java b/src/game/java/net/minecraft/client/particle/EntityDiggingFX.java index fb285bce..4297c79a 100755 --- a/src/game/java/net/minecraft/client/particle/EntityDiggingFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityDiggingFX.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityDropParticleFX.java b/src/game/java/net/minecraft/client/particle/EntityDropParticleFX.java index 87ede835..bb26a3e6 100755 --- a/src/game/java/net/minecraft/client/particle/EntityDropParticleFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityDropParticleFX.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityEnchantmentTableParticleFX.java b/src/game/java/net/minecraft/client/particle/EntityEnchantmentTableParticleFX.java index 2688d220..e9ea1afd 100755 --- a/src/game/java/net/minecraft/client/particle/EntityEnchantmentTableParticleFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityEnchantmentTableParticleFX.java @@ -8,7 +8,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityExplodeFX.java b/src/game/java/net/minecraft/client/particle/EntityExplodeFX.java index 72db7e8b..34073c5f 100755 --- a/src/game/java/net/minecraft/client/particle/EntityExplodeFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityExplodeFX.java @@ -8,7 +8,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityFX.java b/src/game/java/net/minecraft/client/particle/EntityFX.java index 0e55c001..1461a537 100755 --- a/src/game/java/net/minecraft/client/particle/EntityFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityFX.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityFirework.java b/src/game/java/net/minecraft/client/particle/EntityFirework.java index f056d5d4..cf34a400 100755 --- a/src/game/java/net/minecraft/client/particle/EntityFirework.java +++ b/src/game/java/net/minecraft/client/particle/EntityFirework.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityFishWakeFX.java b/src/game/java/net/minecraft/client/particle/EntityFishWakeFX.java index 306c4f90..0ad582ce 100755 --- a/src/game/java/net/minecraft/client/particle/EntityFishWakeFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityFishWakeFX.java @@ -8,7 +8,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityFlameFX.java b/src/game/java/net/minecraft/client/particle/EntityFlameFX.java index 25211987..6c43fe80 100755 --- a/src/game/java/net/minecraft/client/particle/EntityFlameFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityFlameFX.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityFootStepFX.java b/src/game/java/net/minecraft/client/particle/EntityFootStepFX.java index 47cf71ca..2b67f7b5 100755 --- a/src/game/java/net/minecraft/client/particle/EntityFootStepFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityFootStepFX.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityHeartFX.java b/src/game/java/net/minecraft/client/particle/EntityHeartFX.java index 36904ba8..0b05425d 100755 --- a/src/game/java/net/minecraft/client/particle/EntityHeartFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityHeartFX.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityHugeExplodeFX.java b/src/game/java/net/minecraft/client/particle/EntityHugeExplodeFX.java index da950891..d68e60f6 100755 --- a/src/game/java/net/minecraft/client/particle/EntityHugeExplodeFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityHugeExplodeFX.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityLargeExplodeFX.java b/src/game/java/net/minecraft/client/particle/EntityLargeExplodeFX.java index 5f2a9a09..73556ff9 100755 --- a/src/game/java/net/minecraft/client/particle/EntityLargeExplodeFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityLargeExplodeFX.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityLavaFX.java b/src/game/java/net/minecraft/client/particle/EntityLavaFX.java index 8609567c..934ea3dd 100755 --- a/src/game/java/net/minecraft/client/particle/EntityLavaFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityLavaFX.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityNoteFX.java b/src/game/java/net/minecraft/client/particle/EntityNoteFX.java index f0c08249..39f56cbc 100755 --- a/src/game/java/net/minecraft/client/particle/EntityNoteFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityNoteFX.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityParticleEmitter.java b/src/game/java/net/minecraft/client/particle/EntityParticleEmitter.java index 7a137b13..7aadb0a2 100755 --- a/src/game/java/net/minecraft/client/particle/EntityParticleEmitter.java +++ b/src/game/java/net/minecraft/client/particle/EntityParticleEmitter.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityPickupFX.java b/src/game/java/net/minecraft/client/particle/EntityPickupFX.java index 1ba2ca51..e3a9fee1 100755 --- a/src/game/java/net/minecraft/client/particle/EntityPickupFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityPickupFX.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityPortalFX.java b/src/game/java/net/minecraft/client/particle/EntityPortalFX.java index 2ba4f697..9fdee8a2 100755 --- a/src/game/java/net/minecraft/client/particle/EntityPortalFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityPortalFX.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityRainFX.java b/src/game/java/net/minecraft/client/particle/EntityRainFX.java index fb7d561b..b3c3f679 100755 --- a/src/game/java/net/minecraft/client/particle/EntityRainFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityRainFX.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntityReddustFX.java b/src/game/java/net/minecraft/client/particle/EntityReddustFX.java index f4c946b1..04c80907 100755 --- a/src/game/java/net/minecraft/client/particle/EntityReddustFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityReddustFX.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntitySmokeFX.java b/src/game/java/net/minecraft/client/particle/EntitySmokeFX.java index b4469230..e8a56258 100755 --- a/src/game/java/net/minecraft/client/particle/EntitySmokeFX.java +++ b/src/game/java/net/minecraft/client/particle/EntitySmokeFX.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntitySnowShovelFX.java b/src/game/java/net/minecraft/client/particle/EntitySnowShovelFX.java index 7ee48ae4..51bf5e4b 100755 --- a/src/game/java/net/minecraft/client/particle/EntitySnowShovelFX.java +++ b/src/game/java/net/minecraft/client/particle/EntitySnowShovelFX.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntitySpellParticleFX.java b/src/game/java/net/minecraft/client/particle/EntitySpellParticleFX.java index ced40db3..d108bdaf 100755 --- a/src/game/java/net/minecraft/client/particle/EntitySpellParticleFX.java +++ b/src/game/java/net/minecraft/client/particle/EntitySpellParticleFX.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntitySplashFX.java b/src/game/java/net/minecraft/client/particle/EntitySplashFX.java index b37b558b..099b86b3 100755 --- a/src/game/java/net/minecraft/client/particle/EntitySplashFX.java +++ b/src/game/java/net/minecraft/client/particle/EntitySplashFX.java @@ -8,7 +8,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/EntitySuspendFX.java b/src/game/java/net/minecraft/client/particle/EntitySuspendFX.java index d7ca15ec..9ff82ce6 100755 --- a/src/game/java/net/minecraft/client/particle/EntitySuspendFX.java +++ b/src/game/java/net/minecraft/client/particle/EntitySuspendFX.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/IParticleFactory.java b/src/game/java/net/minecraft/client/particle/IParticleFactory.java index f5c34ccf..61bb595d 100755 --- a/src/game/java/net/minecraft/client/particle/IParticleFactory.java +++ b/src/game/java/net/minecraft/client/particle/IParticleFactory.java @@ -8,7 +8,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/particle/MobAppearance.java b/src/game/java/net/minecraft/client/particle/MobAppearance.java index f41648fe..3ba31f60 100755 --- a/src/game/java/net/minecraft/client/particle/MobAppearance.java +++ b/src/game/java/net/minecraft/client/particle/MobAppearance.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/player/inventory/ContainerLocalMenu.java b/src/game/java/net/minecraft/client/player/inventory/ContainerLocalMenu.java index 492bfed5..4dd99c83 100755 --- a/src/game/java/net/minecraft/client/player/inventory/ContainerLocalMenu.java +++ b/src/game/java/net/minecraft/client/player/inventory/ContainerLocalMenu.java @@ -1,9 +1,7 @@ package net.minecraft.client.player.inventory; -import java.util.Map; - -import com.google.common.collect.Maps; - +import com.carrotsearch.hppc.IntIntHashMap; +import com.carrotsearch.hppc.IntIntMap; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.inventory.Container; @@ -18,7 +16,7 @@ import net.minecraft.world.LockCode; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -34,7 +32,7 @@ import net.minecraft.world.LockCode; */ public class ContainerLocalMenu extends InventoryBasic implements ILockableContainer { private String guiID; - private Map field_174895_b = Maps.newHashMap(); + private IntIntMap field_174895_b = new IntIntHashMap(); public ContainerLocalMenu(String id, IChatComponent title, int slotCount) { super(title, slotCount); @@ -42,13 +40,11 @@ public class ContainerLocalMenu extends InventoryBasic implements ILockableConta } public int getField(int i) { - return this.field_174895_b.containsKey(Integer.valueOf(i)) - ? ((Integer) this.field_174895_b.get(Integer.valueOf(i))).intValue() - : 0; + return this.field_174895_b.getOrDefault(i, 0); } public void setField(int i, int j) { - this.field_174895_b.put(Integer.valueOf(i), Integer.valueOf(j)); + this.field_174895_b.put(i, j); } public int getFieldCount() { diff --git a/src/game/java/net/minecraft/client/player/inventory/LocalBlockIntercommunication.java b/src/game/java/net/minecraft/client/player/inventory/LocalBlockIntercommunication.java index 80798e97..38e07c89 100755 --- a/src/game/java/net/minecraft/client/player/inventory/LocalBlockIntercommunication.java +++ b/src/game/java/net/minecraft/client/player/inventory/LocalBlockIntercommunication.java @@ -12,7 +12,7 @@ import net.minecraft.world.IInteractionObject; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/ActiveRenderInfo.java b/src/game/java/net/minecraft/client/renderer/ActiveRenderInfo.java index 3dbffbd4..54a36ad5 100755 --- a/src/game/java/net/minecraft/client/renderer/ActiveRenderInfo.java +++ b/src/game/java/net/minecraft/client/renderer/ActiveRenderInfo.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/BlockFluidRenderer.java b/src/game/java/net/minecraft/client/renderer/BlockFluidRenderer.java index 4f010ac3..d3bd7963 100755 --- a/src/game/java/net/minecraft/client/renderer/BlockFluidRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/BlockFluidRenderer.java @@ -22,7 +22,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/BlockModelRenderer.java b/src/game/java/net/minecraft/client/renderer/BlockModelRenderer.java index 17e4d2e4..59e28721 100755 --- a/src/game/java/net/minecraft/client/renderer/BlockModelRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/BlockModelRenderer.java @@ -30,7 +30,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/BlockModelShapes.java b/src/game/java/net/minecraft/client/renderer/BlockModelShapes.java index 7fdd1e77..4642280d 100755 --- a/src/game/java/net/minecraft/client/renderer/BlockModelShapes.java +++ b/src/game/java/net/minecraft/client/renderer/BlockModelShapes.java @@ -65,7 +65,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/BlockRendererDispatcher.java b/src/game/java/net/minecraft/client/renderer/BlockRendererDispatcher.java index 32062476..167028a7 100755 --- a/src/game/java/net/minecraft/client/renderer/BlockRendererDispatcher.java +++ b/src/game/java/net/minecraft/client/renderer/BlockRendererDispatcher.java @@ -23,7 +23,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/ChestRenderer.java b/src/game/java/net/minecraft/client/renderer/ChestRenderer.java index 4a2d4036..ef02766c 100755 --- a/src/game/java/net/minecraft/client/renderer/ChestRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/ChestRenderer.java @@ -11,7 +11,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/ChunkRenderContainer.java b/src/game/java/net/minecraft/client/renderer/ChunkRenderContainer.java index fe70e7e3..bce02f9c 100755 --- a/src/game/java/net/minecraft/client/renderer/ChunkRenderContainer.java +++ b/src/game/java/net/minecraft/client/renderer/ChunkRenderContainer.java @@ -18,7 +18,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/DestroyBlockProgress.java b/src/game/java/net/minecraft/client/renderer/DestroyBlockProgress.java index 10db86d6..94517046 100755 --- a/src/game/java/net/minecraft/client/renderer/DestroyBlockProgress.java +++ b/src/game/java/net/minecraft/client/renderer/DestroyBlockProgress.java @@ -8,7 +8,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/EntityRenderer.java b/src/game/java/net/minecraft/client/renderer/EntityRenderer.java index 04b40a5a..b1112f72 100755 --- a/src/game/java/net/minecraft/client/renderer/EntityRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/EntityRenderer.java @@ -97,7 +97,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -1928,7 +1928,7 @@ public class EntityRenderer implements IResourceManagerReloadListener { // System.out.println(builder.toString()); float waveTimer = (float) ((EagRuntime.steadyTimeMillis() % 600000l) * 0.001); - DeferredStateManager.setWaterWindOffset(0.0f, 0.0f, waveTimer, waveTimer); + DeferredStateManager.setWaterWindOffset(waveTimer * 0.25f, waveTimer * 0.13f, waveTimer * 1.45f, waveTimer); float blockWaveDistX = (float) (d0 - blockWaveOffsetX); float blockWaveDistY = (float) (d1 - blockWaveOffsetY); @@ -2563,7 +2563,7 @@ public class EntityRenderer implements IResourceManagerReloadListener { + mc.theWorld.getThunderStrength(partialTicks) * 5.0f; ds *= MathHelper.clamp_float(6.0f - DeferredStateManager.getSunHeight() * 17.0f, 1.0f, 3.0f); if (conf.is_rendering_lightShafts) { - ds *= Math.max(2.0f - Math.abs(DeferredStateManager.getSunHeight()) * 5.0f, 1.0f); + ds *= Math.max(2.5f - Math.abs(DeferredStateManager.getSunHeight()) * 5.0f, 2.5f); } DeferredStateManager.enableFogExp(ds, true, 1.0f, 1.0f, 1.0f, 1.0f, ff, ff, ff, 1.0f); } @@ -2661,6 +2661,7 @@ public class EntityRenderer implements IResourceManagerReloadListener { for (int i = 0, l = lst.size(); i < l; ++i) { lst.get(i).draw(ShadersRenderPassFuture.PassType.MAIN); } + DeferredStateManager.forwardCallbackGBuffer.reset(); GlStateManager.matrixMode(GL_PROJECTION); GlStateManager.popMatrix(); GlStateManager.matrixMode(GL_MODELVIEW); diff --git a/src/game/java/net/minecraft/client/renderer/EnumFaceDirection.java b/src/game/java/net/minecraft/client/renderer/EnumFaceDirection.java index 2717926d..e548cf5a 100755 --- a/src/game/java/net/minecraft/client/renderer/EnumFaceDirection.java +++ b/src/game/java/net/minecraft/client/renderer/EnumFaceDirection.java @@ -8,7 +8,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/GLAllocation.java b/src/game/java/net/minecraft/client/renderer/GLAllocation.java index 04ac9489..bbfbfb19 100755 --- a/src/game/java/net/minecraft/client/renderer/GLAllocation.java +++ b/src/game/java/net/minecraft/client/renderer/GLAllocation.java @@ -13,7 +13,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/IImageBuffer.java b/src/game/java/net/minecraft/client/renderer/IImageBuffer.java index b0f39a48..9ef18958 100755 --- a/src/game/java/net/minecraft/client/renderer/IImageBuffer.java +++ b/src/game/java/net/minecraft/client/renderer/IImageBuffer.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.ImageData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/ImageBufferDownload.java b/src/game/java/net/minecraft/client/renderer/ImageBufferDownload.java index 971e9ea5..45038ac1 100755 --- a/src/game/java/net/minecraft/client/renderer/ImageBufferDownload.java +++ b/src/game/java/net/minecraft/client/renderer/ImageBufferDownload.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.ImageData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/InventoryEffectRenderer.java b/src/game/java/net/minecraft/client/renderer/InventoryEffectRenderer.java index 34a862dc..217010e5 100755 --- a/src/game/java/net/minecraft/client/renderer/InventoryEffectRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/InventoryEffectRenderer.java @@ -1,6 +1,7 @@ package net.minecraft.client.renderer; -import java.util.Collection; +import com.carrotsearch.hppc.ObjectContainer; +import com.carrotsearch.hppc.cursors.ObjectCursor; import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager; import net.minecraft.client.gui.inventory.GuiContainer; @@ -15,7 +16,7 @@ import net.minecraft.potion.PotionEffect; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -76,7 +77,7 @@ public abstract class InventoryEffectRenderer extends GuiContainer { int i = this.guiLeft - 124; int j = this.guiTop; boolean flag = true; - Collection collection = this.mc.thePlayer.getActivePotionEffects(); + ObjectContainer collection = this.mc.thePlayer.getActivePotionEffects(); if (!collection.isEmpty()) { GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.disableLighting(); @@ -86,7 +87,8 @@ public abstract class InventoryEffectRenderer extends GuiContainer { k = 132 / (collection.size() - 1); } - for (PotionEffect potioneffect : this.mc.thePlayer.getActivePotionEffects()) { + for (ObjectCursor potioneffect_ : collection) { + PotionEffect potioneffect = potioneffect_.value; Potion potion = Potion.potionTypes[potioneffect.getPotionID()]; GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); this.mc.getTextureManager().bindTexture(inventoryBackground); diff --git a/src/game/java/net/minecraft/client/renderer/ItemMeshDefinition.java b/src/game/java/net/minecraft/client/renderer/ItemMeshDefinition.java index 525fea0b..78fd4bd2 100755 --- a/src/game/java/net/minecraft/client/renderer/ItemMeshDefinition.java +++ b/src/game/java/net/minecraft/client/renderer/ItemMeshDefinition.java @@ -9,7 +9,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/ItemModelMesher.java b/src/game/java/net/minecraft/client/renderer/ItemModelMesher.java index 7d29771f..82d853e9 100755 --- a/src/game/java/net/minecraft/client/renderer/ItemModelMesher.java +++ b/src/game/java/net/minecraft/client/renderer/ItemModelMesher.java @@ -1,8 +1,9 @@ package net.minecraft.client.renderer; import java.util.Map; -import java.util.Map.Entry; - +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; +import com.carrotsearch.hppc.cursors.IntObjectCursor; import com.google.common.collect.Maps; import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerTextureAtlasSprite; @@ -18,7 +19,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -33,8 +34,8 @@ import net.minecraft.item.ItemStack; * */ public class ItemModelMesher { - private final Map simpleShapes = Maps.newHashMap(); - private final Map simpleShapesCache = Maps.newHashMap(); + private final IntObjectMap simpleShapes = new IntObjectHashMap<>(); + private final IntObjectMap simpleShapesCache = new IntObjectHashMap<>(); private final Map shapers = Maps.newHashMap(); private final ModelManager modelManager; @@ -54,7 +55,7 @@ public class ItemModelMesher { Item item = stack.getItem(); IBakedModel ibakedmodel = this.getItemModel(item, this.getMetadata(stack)); if (ibakedmodel == null) { - ItemMeshDefinition itemmeshdefinition = (ItemMeshDefinition) this.shapers.get(item); + ItemMeshDefinition itemmeshdefinition = this.shapers.get(item); if (itemmeshdefinition != null) { ibakedmodel = this.modelManager.getModel(itemmeshdefinition.getModelLocation(stack)); } @@ -72,7 +73,7 @@ public class ItemModelMesher { } protected IBakedModel getItemModel(Item item, int meta) { - return (IBakedModel) this.simpleShapesCache.get(Integer.valueOf(this.getIndex(item, meta))); + return this.simpleShapesCache.get(this.getIndex(item, meta)); } private int getIndex(Item item, int meta) { @@ -80,8 +81,8 @@ public class ItemModelMesher { } public void register(Item item, int meta, ModelResourceLocation location) { - this.simpleShapes.put(Integer.valueOf(this.getIndex(item, meta)), location); - this.simpleShapesCache.put(Integer.valueOf(this.getIndex(item, meta)), this.modelManager.getModel(location)); + this.simpleShapes.put(this.getIndex(item, meta), location); + this.simpleShapesCache.put(this.getIndex(item, meta), this.modelManager.getModel(location)); } public void register(Item item, ItemMeshDefinition definition) { @@ -95,10 +96,8 @@ public class ItemModelMesher { public void rebuildCache() { this.simpleShapesCache.clear(); - for (Entry entry : this.simpleShapes.entrySet()) { - this.simpleShapesCache.put((Integer) entry.getKey(), - this.modelManager.getModel((ModelResourceLocation) entry.getValue())); + for (IntObjectCursor entry : this.simpleShapes) { + this.simpleShapesCache.put(entry.key, this.modelManager.getModel(entry.value)); } - } } \ No newline at end of file diff --git a/src/game/java/net/minecraft/client/renderer/ItemRenderer.java b/src/game/java/net/minecraft/client/renderer/ItemRenderer.java index 101f61e3..a15f38d8 100755 --- a/src/game/java/net/minecraft/client/renderer/ItemRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/ItemRenderer.java @@ -37,7 +37,7 @@ import net.minecraft.world.storage.MapData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -193,7 +193,7 @@ public class ItemRenderer { this.mc.getTextureManager().bindTexture(RES_MAP_BACKGROUND); Tessellator tessellator = Tessellator.getInstance(); WorldRenderer worldrenderer = tessellator.getWorldRenderer(); - EaglercraftGPU.glNormal3f(0.0F, 0.0F, -1.0F); + EaglercraftGPU.glNormal3f(0.0F, 0.0F, 1.0F); worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); worldrenderer.pos(-7.0D, 135.0D, 0.0D).tex(0.0D, 1.0D).endVertex(); worldrenderer.pos(135.0D, 135.0D, 0.0D).tex(1.0D, 1.0D).endVertex(); diff --git a/src/game/java/net/minecraft/client/renderer/RegionRenderCache.java b/src/game/java/net/minecraft/client/renderer/RegionRenderCache.java index 8736fc03..6141b1a4 100755 --- a/src/game/java/net/minecraft/client/renderer/RegionRenderCache.java +++ b/src/game/java/net/minecraft/client/renderer/RegionRenderCache.java @@ -9,6 +9,7 @@ import net.minecraft.util.BlockPos; import net.minecraft.util.Vec3i; import net.minecraft.world.ChunkCache; import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; import net.minecraft.world.chunk.Chunk; /**+ @@ -17,7 +18,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -34,16 +35,19 @@ import net.minecraft.world.chunk.Chunk; public class RegionRenderCache extends ChunkCache { private final IBlockState DEFAULT_STATE = Blocks.air.getDefaultState(); private final BlockPos position; - private int[] combinedLights; - private IBlockState[] blockStates; + private final BlockPos tmpStupid = new BlockPos(); + private static final int[] combinedLights = new int[8000]; + private static final IBlockState[] blockStates = new IBlockState[8000]; + private static final int[] biomeColors = new int[1200]; + private static final int[] biomeColorsBlended = new int[768]; public RegionRenderCache(World worldIn, BlockPos posFromIn, BlockPos posToIn, int subIn) { super(worldIn, posFromIn, posToIn, subIn); this.position = posFromIn.subtract(new Vec3i(subIn, subIn, subIn)); - boolean flag = true; - this.combinedLights = new int[8000]; - Arrays.fill(this.combinedLights, -1); - this.blockStates = new IBlockState[8000]; + Arrays.fill(combinedLights, -1); + Arrays.fill(blockStates, null); + Arrays.fill(biomeColors, 0); + Arrays.fill(biomeColorsBlended, 0); } public TileEntity getTileEntity(BlockPos blockpos) { @@ -54,10 +58,10 @@ public class RegionRenderCache extends ChunkCache { public int getCombinedLight(BlockPos blockpos, int i) { int j = this.getPositionIndex(blockpos); - int k = this.combinedLights[j]; + int k = combinedLights[j]; if (k == -1) { k = super.getCombinedLight(blockpos, i); - this.combinedLights[j] = k; + combinedLights[j] = k; } return k; @@ -65,10 +69,10 @@ public class RegionRenderCache extends ChunkCache { public IBlockState getBlockState(BlockPos blockpos) { int i = this.getPositionIndex(blockpos); - IBlockState iblockstate = this.blockStates[i]; + IBlockState iblockstate = blockStates[i]; if (iblockstate == null) { iblockstate = this.getBlockStateRaw(blockpos); - this.blockStates[i] = iblockstate; + blockStates[i] = iblockstate; } return iblockstate; @@ -79,15 +83,29 @@ public class RegionRenderCache extends ChunkCache { */ public IBlockState getBlockStateFaster(BlockPos blockpos) { int i = this.getPositionIndexFaster(blockpos); - IBlockState iblockstate = this.blockStates[i]; + IBlockState iblockstate = blockStates[i]; if (iblockstate == null) { iblockstate = this.getBlockStateRawFaster(blockpos); - this.blockStates[i] = iblockstate; + blockStates[i] = iblockstate; } return iblockstate; } + /** + * only use with a regular "net.minecraft.util.BlockPos"! + */ + public int getBiomeColorForCoords(BlockPos blockpos, int colorIndex) { + int i = this.getPositionIndex16Faster(blockpos); + i += colorIndex * 256; + int j = biomeColorsBlended[i]; + if (j == 0) { + j = getBiomeColorBlended(blockpos, colorIndex); + biomeColorsBlended[i] = j; + } + return j; + } + private IBlockState getBlockStateRaw(BlockPos pos) { if (pos.getY() >= 0 && pos.getY() < 256) { int i = (pos.getX() >> 4) - this.chunkX; @@ -111,6 +129,59 @@ public class RegionRenderCache extends ChunkCache { } } + private int getBiomeColorBlended(BlockPos blockpos, int colorIndex) { + BlockPos blockpos2 = tmpStupid; + blockpos2.y = blockpos.y; + int rad = 1; + int xmin = blockpos.x - rad; + int zmin = blockpos.z - rad; + int xmax = blockpos.x + rad; + int zmax = blockpos.z + rad; + int r = 0; + int g = 0; + int b = 0; + int rgb; + for (int x = xmin; x <= xmax; ++x) { + for (int z = zmin; z <= zmax; ++z) { + blockpos2.x = x; + blockpos2.z = z; + rgb = getBiomeColorRaw(blockpos2, colorIndex); + r += (rgb >> 16) & 0xFF; + g += (rgb >> 8) & 0xFF; + b += rgb & 0xFF; + } + } + rad = 1 + rad * 2; + rad *= rad; + return 0xFF000000 | ((r / rad) << 16) | ((g / rad) << 8) | (b / rad); + } + + private int getBiomeColorRaw(BlockPos blockpos, int colorIndex) { + int i = getPositionIndex20Faster(blockpos); + i += colorIndex * 400; + int j = biomeColors[i]; + BiomeGenBase biome; + int ii, jj; + if (j == 0) { + if (blockpos.y >= 0 && blockpos.y < 256) { + ii = (blockpos.x >> 4) - this.chunkX; + jj = (blockpos.z >> 4) - this.chunkZ; + biome = this.chunkArray[ii][jj].getBiome(blockpos, worldObj.getWorldChunkManager()); + if (colorIndex == 0) { + j = biome.getGrassColorAtPos(blockpos); + } else if (colorIndex == 1) { + j = biome.getFoliageColorAtPos(blockpos); + } else { + j = biome.waterColorMultiplier; + } + } else { + j = 0xFFFFFFFF; + } + biomeColors[i] = j; + } + return j; + } + private int getPositionIndex(BlockPos parBlockPos) { int i = parBlockPos.getX() - this.position.getX(); int j = parBlockPos.getY() - this.position.getY(); @@ -127,4 +198,19 @@ public class RegionRenderCache extends ChunkCache { int k = parBlockPos.z - this.position.z; return i * 400 + k * 20 + j; } + + /** + * only use with a regular "net.minecraft.util.BlockPos"! + */ + private int getPositionIndex16Faster(BlockPos parBlockPos) { + int i = parBlockPos.x - this.position.x - 2; + int k = parBlockPos.z - this.position.z - 2; + return i * 16 + k; + } + + private int getPositionIndex20Faster(BlockPos parBlockPos) { + int i = parBlockPos.x - this.position.x; + int k = parBlockPos.z - this.position.z; + return i * 20 + k; + } } \ No newline at end of file diff --git a/src/game/java/net/minecraft/client/renderer/RegionRenderCacheBuilder.java b/src/game/java/net/minecraft/client/renderer/RegionRenderCacheBuilder.java index f758d159..ec3ab628 100755 --- a/src/game/java/net/minecraft/client/renderer/RegionRenderCacheBuilder.java +++ b/src/game/java/net/minecraft/client/renderer/RegionRenderCacheBuilder.java @@ -9,7 +9,7 @@ import net.minecraft.util.EnumWorldBlockLayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/RenderGlobal.java b/src/game/java/net/minecraft/client/renderer/RenderGlobal.java index 90e0a698..a6c19d43 100755 --- a/src/game/java/net/minecraft/client/renderer/RenderGlobal.java +++ b/src/game/java/net/minecraft/client/renderer/RenderGlobal.java @@ -104,7 +104,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/RenderHelper.java b/src/game/java/net/minecraft/client/renderer/RenderHelper.java index 2a1800da..47fe4f9b 100755 --- a/src/game/java/net/minecraft/client/renderer/RenderHelper.java +++ b/src/game/java/net/minecraft/client/renderer/RenderHelper.java @@ -12,7 +12,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/RenderList.java b/src/game/java/net/minecraft/client/renderer/RenderList.java index 7d9d4e32..d1376d96 100755 --- a/src/game/java/net/minecraft/client/renderer/RenderList.java +++ b/src/game/java/net/minecraft/client/renderer/RenderList.java @@ -11,7 +11,7 @@ import net.minecraft.util.EnumWorldBlockLayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/StitcherException.java b/src/game/java/net/minecraft/client/renderer/StitcherException.java index b0f2e444..6d21c8af 100755 --- a/src/game/java/net/minecraft/client/renderer/StitcherException.java +++ b/src/game/java/net/minecraft/client/renderer/StitcherException.java @@ -8,7 +8,7 @@ import net.minecraft.client.renderer.texture.Stitcher; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/Tessellator.java b/src/game/java/net/minecraft/client/renderer/Tessellator.java index 191311c3..6a607576 100755 --- a/src/game/java/net/minecraft/client/renderer/Tessellator.java +++ b/src/game/java/net/minecraft/client/renderer/Tessellator.java @@ -10,7 +10,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.WorldVertexBufferUploader; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/ViewFrustum.java b/src/game/java/net/minecraft/client/renderer/ViewFrustum.java index dcd529ce..bb1f6983 100755 --- a/src/game/java/net/minecraft/client/renderer/ViewFrustum.java +++ b/src/game/java/net/minecraft/client/renderer/ViewFrustum.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/block/model/BakedQuad.java b/src/game/java/net/minecraft/client/renderer/block/model/BakedQuad.java index d5226146..05aab3ab 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/BakedQuad.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/BakedQuad.java @@ -8,7 +8,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/block/model/BlockFaceUV.java b/src/game/java/net/minecraft/client/renderer/block/model/BlockFaceUV.java index 498cede9..61d0696f 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/BlockFaceUV.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/BlockFaceUV.java @@ -12,7 +12,7 @@ import net.lax1dude.eaglercraft.v1_8.json.JSONTypeDeserializer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/block/model/BlockPart.java b/src/game/java/net/minecraft/client/renderer/block/model/BlockPart.java index 242db3d4..f156340c 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/BlockPart.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/BlockPart.java @@ -22,7 +22,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/block/model/BlockPartFace.java b/src/game/java/net/minecraft/client/renderer/block/model/BlockPartFace.java index c945f20b..c299ef8e 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/BlockPartFace.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/BlockPartFace.java @@ -13,7 +13,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/block/model/BlockPartRotation.java b/src/game/java/net/minecraft/client/renderer/block/model/BlockPartRotation.java index 11972b0f..fc2b970a 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/BlockPartRotation.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/BlockPartRotation.java @@ -9,7 +9,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/block/model/BreakingFour.java b/src/game/java/net/minecraft/client/renderer/block/model/BreakingFour.java index 46d6dc23..9256a2d1 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/BreakingFour.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/BreakingFour.java @@ -10,7 +10,7 @@ import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerTextureAtlasSprite; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/block/model/FaceBakery.java b/src/game/java/net/minecraft/client/renderer/block/model/FaceBakery.java index 28a1387a..edd2c385 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/FaceBakery.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/FaceBakery.java @@ -18,7 +18,7 @@ import net.minecraft.util.Vec3i; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/block/model/ItemCameraTransforms.java b/src/game/java/net/minecraft/client/renderer/block/model/ItemCameraTransforms.java index 2a6e06d0..ef0d8ba5 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/ItemCameraTransforms.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/ItemCameraTransforms.java @@ -13,7 +13,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/block/model/ItemModelGenerator.java b/src/game/java/net/minecraft/client/renderer/block/model/ItemModelGenerator.java index 790e8c83..a8d39aa3 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/ItemModelGenerator.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/ItemModelGenerator.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/block/model/ItemTransformVec3f.java b/src/game/java/net/minecraft/client/renderer/block/model/ItemTransformVec3f.java index dfc10aa1..258e06c7 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/ItemTransformVec3f.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/ItemTransformVec3f.java @@ -14,7 +14,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/block/model/ModelBlock.java b/src/game/java/net/minecraft/client/renderer/block/model/ModelBlock.java index 5e0f330e..83677fd3 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/ModelBlock.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/ModelBlock.java @@ -24,7 +24,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/block/model/ModelBlockDefinition.java b/src/game/java/net/minecraft/client/renderer/block/model/ModelBlockDefinition.java index 2ef74f4d..68f51dac 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/ModelBlockDefinition.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/ModelBlockDefinition.java @@ -23,7 +23,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/block/statemap/BlockStateMapper.java b/src/game/java/net/minecraft/client/renderer/block/statemap/BlockStateMapper.java index ada6e6b9..0dfd2b12 100755 --- a/src/game/java/net/minecraft/client/renderer/block/statemap/BlockStateMapper.java +++ b/src/game/java/net/minecraft/client/renderer/block/statemap/BlockStateMapper.java @@ -19,7 +19,7 @@ import net.minecraft.client.resources.model.ModelResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/block/statemap/DefaultStateMapper.java b/src/game/java/net/minecraft/client/renderer/block/statemap/DefaultStateMapper.java index 396d62e3..bb74f3ed 100755 --- a/src/game/java/net/minecraft/client/renderer/block/statemap/DefaultStateMapper.java +++ b/src/game/java/net/minecraft/client/renderer/block/statemap/DefaultStateMapper.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/block/statemap/IStateMapper.java b/src/game/java/net/minecraft/client/renderer/block/statemap/IStateMapper.java index 0058edae..4e2af2ef 100755 --- a/src/game/java/net/minecraft/client/renderer/block/statemap/IStateMapper.java +++ b/src/game/java/net/minecraft/client/renderer/block/statemap/IStateMapper.java @@ -12,7 +12,7 @@ import net.minecraft.client.resources.model.ModelResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/block/statemap/StateMap.java b/src/game/java/net/minecraft/client/renderer/block/statemap/StateMap.java index 95148123..ec3c53cc 100755 --- a/src/game/java/net/minecraft/client/renderer/block/statemap/StateMap.java +++ b/src/game/java/net/minecraft/client/renderer/block/statemap/StateMap.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/block/statemap/StateMapperBase.java b/src/game/java/net/minecraft/client/renderer/block/statemap/StateMapperBase.java index 0157f33a..1665c3dd 100755 --- a/src/game/java/net/minecraft/client/renderer/block/statemap/StateMapperBase.java +++ b/src/game/java/net/minecraft/client/renderer/block/statemap/StateMapperBase.java @@ -16,7 +16,7 @@ import net.minecraft.client.resources.model.ModelResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/chunk/ChunkCompileTaskGenerator.java b/src/game/java/net/minecraft/client/renderer/chunk/ChunkCompileTaskGenerator.java index dab798c2..1250cdd8 100755 --- a/src/game/java/net/minecraft/client/renderer/chunk/ChunkCompileTaskGenerator.java +++ b/src/game/java/net/minecraft/client/renderer/chunk/ChunkCompileTaskGenerator.java @@ -14,7 +14,7 @@ import net.minecraft.util.EnumWorldBlockLayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/chunk/ChunkRenderWorker.java b/src/game/java/net/minecraft/client/renderer/chunk/ChunkRenderWorker.java index ced087ff..06e6654a 100755 --- a/src/game/java/net/minecraft/client/renderer/chunk/ChunkRenderWorker.java +++ b/src/game/java/net/minecraft/client/renderer/chunk/ChunkRenderWorker.java @@ -15,7 +15,7 @@ import net.minecraft.util.EnumWorldBlockLayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/chunk/CompiledChunk.java b/src/game/java/net/minecraft/client/renderer/chunk/CompiledChunk.java index 19e07b1c..85bb0ff5 100755 --- a/src/game/java/net/minecraft/client/renderer/chunk/CompiledChunk.java +++ b/src/game/java/net/minecraft/client/renderer/chunk/CompiledChunk.java @@ -16,7 +16,7 @@ import net.minecraft.util.EnumWorldBlockLayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/chunk/IRenderChunkFactory.java b/src/game/java/net/minecraft/client/renderer/chunk/IRenderChunkFactory.java index 3451a15e..0554c0a5 100755 --- a/src/game/java/net/minecraft/client/renderer/chunk/IRenderChunkFactory.java +++ b/src/game/java/net/minecraft/client/renderer/chunk/IRenderChunkFactory.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/chunk/ListChunkFactory.java b/src/game/java/net/minecraft/client/renderer/chunk/ListChunkFactory.java index ac5180af..5cd218a0 100755 --- a/src/game/java/net/minecraft/client/renderer/chunk/ListChunkFactory.java +++ b/src/game/java/net/minecraft/client/renderer/chunk/ListChunkFactory.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/chunk/ListedRenderChunk.java b/src/game/java/net/minecraft/client/renderer/chunk/ListedRenderChunk.java index 7c85cd3e..23369a00 100755 --- a/src/game/java/net/minecraft/client/renderer/chunk/ListedRenderChunk.java +++ b/src/game/java/net/minecraft/client/renderer/chunk/ListedRenderChunk.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/chunk/RenderChunk.java b/src/game/java/net/minecraft/client/renderer/chunk/RenderChunk.java index fabb56d9..05fb6b6e 100755 --- a/src/game/java/net/minecraft/client/renderer/chunk/RenderChunk.java +++ b/src/game/java/net/minecraft/client/renderer/chunk/RenderChunk.java @@ -1,7 +1,5 @@ package net.minecraft.client.renderer.chunk; -import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; - import java.util.EnumMap; import java.util.HashSet; import java.util.Set; @@ -9,7 +7,6 @@ import java.util.Set; import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager; import net.lax1dude.eaglercraft.v1_8.opengl.VertexFormat; import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.DeferredStateManager; @@ -36,7 +33,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -63,7 +60,6 @@ public class RenderChunk { private ChunkCompileTaskGenerator compileTask = null; private final Set field_181056_j = Sets.newHashSet(); private final int index; - private final float[] modelviewMatrix = new float[16]; public AxisAlignedBB boundingBox; private int frameIndex = -1; private boolean needsUpdate = true; @@ -103,8 +99,6 @@ public class RenderChunk { for (int i = 0; i < facings.length; ++i) { this.field_181702_p.put(facings[i], pos.offset(facings[i], 16)); } - - this.initModelviewMatrix(); } public void resortTransparency(float x, float y, float z, ChunkCompileTaskGenerator generator) { @@ -272,21 +266,6 @@ public class RenderChunk { worldRendererIn.finishDrawing(); } - private void initModelviewMatrix() { - GlStateManager.pushMatrix(); - GlStateManager.loadIdentity(); - float f = 1.000001F; - GlStateManager.translate(-8.0F, -8.0F, -8.0F); - GlStateManager.scale(f, f, f); - GlStateManager.translate(8.0F, 8.0F, 8.0F); - GlStateManager.getFloat(GL_MODELVIEW_MATRIX, this.modelviewMatrix); - GlStateManager.popMatrix(); - } - - public void multModelviewMatrix() { - GlStateManager.multMatrix(this.modelviewMatrix); - } - public CompiledChunk getCompiledChunk() { return this.compiledChunk; } diff --git a/src/game/java/net/minecraft/client/renderer/chunk/SetVisibility.java b/src/game/java/net/minecraft/client/renderer/chunk/SetVisibility.java index b6a0f00a..22937ea2 100755 --- a/src/game/java/net/minecraft/client/renderer/chunk/SetVisibility.java +++ b/src/game/java/net/minecraft/client/renderer/chunk/SetVisibility.java @@ -11,7 +11,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/chunk/VisGraph.java b/src/game/java/net/minecraft/client/renderer/chunk/VisGraph.java index a65bad52..48ccf81e 100755 --- a/src/game/java/net/minecraft/client/renderer/chunk/VisGraph.java +++ b/src/game/java/net/minecraft/client/renderer/chunk/VisGraph.java @@ -17,7 +17,7 @@ import net.minecraft.util.IntegerCache; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/culling/ClippingHelper.java b/src/game/java/net/minecraft/client/renderer/culling/ClippingHelper.java index 8a422b55..9f51f9f2 100755 --- a/src/game/java/net/minecraft/client/renderer/culling/ClippingHelper.java +++ b/src/game/java/net/minecraft/client/renderer/culling/ClippingHelper.java @@ -6,7 +6,7 @@ package net.minecraft.client.renderer.culling; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/culling/ClippingHelperImpl.java b/src/game/java/net/minecraft/client/renderer/culling/ClippingHelperImpl.java index 869ed429..07a48355 100755 --- a/src/game/java/net/minecraft/client/renderer/culling/ClippingHelperImpl.java +++ b/src/game/java/net/minecraft/client/renderer/culling/ClippingHelperImpl.java @@ -11,7 +11,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/culling/Frustum.java b/src/game/java/net/minecraft/client/renderer/culling/Frustum.java index 4677c9a9..af42994d 100755 --- a/src/game/java/net/minecraft/client/renderer/culling/Frustum.java +++ b/src/game/java/net/minecraft/client/renderer/culling/Frustum.java @@ -8,7 +8,7 @@ import net.minecraft.util.AxisAlignedBB; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/culling/ICamera.java b/src/game/java/net/minecraft/client/renderer/culling/ICamera.java index 05029c24..b042cbd7 100755 --- a/src/game/java/net/minecraft/client/renderer/culling/ICamera.java +++ b/src/game/java/net/minecraft/client/renderer/culling/ICamera.java @@ -8,7 +8,7 @@ import net.minecraft.util.AxisAlignedBB; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/ArmorStandRenderer.java b/src/game/java/net/minecraft/client/renderer/entity/ArmorStandRenderer.java index e0165299..18fdc2bf 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/ArmorStandRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/entity/ArmorStandRenderer.java @@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/Render.java b/src/game/java/net/minecraft/client/renderer/entity/Render.java index ed72da15..26848e50 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/Render.java +++ b/src/game/java/net/minecraft/client/renderer/entity/Render.java @@ -34,7 +34,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderArrow.java b/src/game/java/net/minecraft/client/renderer/entity/RenderArrow.java index dea483ff..217f6639 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderArrow.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderArrow.java @@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderBat.java b/src/game/java/net/minecraft/client/renderer/entity/RenderBat.java index de47b45a..52df3d0c 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderBat.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderBat.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderBiped.java b/src/game/java/net/minecraft/client/renderer/entity/RenderBiped.java index 2e10a1eb..9149a91f 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderBiped.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderBiped.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderBlaze.java b/src/game/java/net/minecraft/client/renderer/entity/RenderBlaze.java index 209c1fcf..a9ee2eff 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderBlaze.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderBlaze.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderBoat.java b/src/game/java/net/minecraft/client/renderer/entity/RenderBoat.java index 3a24dccb..26f95235 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderBoat.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderBoat.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderCaveSpider.java b/src/game/java/net/minecraft/client/renderer/entity/RenderCaveSpider.java index 73714ead..05095356 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderCaveSpider.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderCaveSpider.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderChicken.java b/src/game/java/net/minecraft/client/renderer/entity/RenderChicken.java index 46d64266..edaee657 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderChicken.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderChicken.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderCow.java b/src/game/java/net/minecraft/client/renderer/entity/RenderCow.java index 1c8f4fc1..f819782c 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderCow.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderCow.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderCreeper.java b/src/game/java/net/minecraft/client/renderer/entity/RenderCreeper.java index 80b52ada..2c094400 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderCreeper.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderCreeper.java @@ -14,7 +14,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderDragon.java b/src/game/java/net/minecraft/client/renderer/entity/RenderDragon.java index 4b48981d..c0254d76 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderDragon.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderDragon.java @@ -22,7 +22,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderEnderman.java b/src/game/java/net/minecraft/client/renderer/entity/RenderEnderman.java index 774c731d..82468296 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderEnderman.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderEnderman.java @@ -14,7 +14,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderEndermite.java b/src/game/java/net/minecraft/client/renderer/entity/RenderEndermite.java index 50a75907..73662b36 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderEndermite.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderEndermite.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderEntity.java b/src/game/java/net/minecraft/client/renderer/entity/RenderEntity.java index 23e95203..57d89bf6 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderEntity.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderEntity.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderEntityItem.java b/src/game/java/net/minecraft/client/renderer/entity/RenderEntityItem.java index 4cf405d1..e7464425 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderEntityItem.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderEntityItem.java @@ -21,7 +21,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderFallingBlock.java b/src/game/java/net/minecraft/client/renderer/entity/RenderFallingBlock.java index 313e2135..5121efdf 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderFallingBlock.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderFallingBlock.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderFireball.java b/src/game/java/net/minecraft/client/renderer/entity/RenderFireball.java index 09113405..9b7b4d6d 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderFireball.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderFireball.java @@ -17,7 +17,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderFish.java b/src/game/java/net/minecraft/client/renderer/entity/RenderFish.java index 4476f969..ea77184c 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderFish.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderFish.java @@ -16,7 +16,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderGhast.java b/src/game/java/net/minecraft/client/renderer/entity/RenderGhast.java index 714e6486..64b32362 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderGhast.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderGhast.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderGiantZombie.java b/src/game/java/net/minecraft/client/renderer/entity/RenderGiantZombie.java index bc353b06..f1793129 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderGiantZombie.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderGiantZombie.java @@ -14,7 +14,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderGuardian.java b/src/game/java/net/minecraft/client/renderer/entity/RenderGuardian.java index 28c29606..085a13ee 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderGuardian.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderGuardian.java @@ -22,7 +22,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderHorse.java b/src/game/java/net/minecraft/client/renderer/entity/RenderHorse.java index 64f2384b..6e936509 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderHorse.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderHorse.java @@ -17,7 +17,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderIronGolem.java b/src/game/java/net/minecraft/client/renderer/entity/RenderIronGolem.java index 4fb6c90e..2590f782 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderIronGolem.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderIronGolem.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderItem.java b/src/game/java/net/minecraft/client/renderer/entity/RenderItem.java index 715a8d04..ab048805 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderItem.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderItem.java @@ -73,7 +73,7 @@ import net.minecraft.util.Vec3i; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderLeashKnot.java b/src/game/java/net/minecraft/client/renderer/entity/RenderLeashKnot.java index 06578ecc..f6a6990f 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderLeashKnot.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderLeashKnot.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderLightningBolt.java b/src/game/java/net/minecraft/client/renderer/entity/RenderLightningBolt.java index ad444058..3b178b20 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderLightningBolt.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderLightningBolt.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderLiving.java b/src/game/java/net/minecraft/client/renderer/entity/RenderLiving.java index 5195fd51..46792ee9 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderLiving.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderLiving.java @@ -17,7 +17,7 @@ import net.minecraft.entity.EntityLiving; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderMagmaCube.java b/src/game/java/net/minecraft/client/renderer/entity/RenderMagmaCube.java index 733c248b..e6ba5067 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderMagmaCube.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderMagmaCube.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderManager.java b/src/game/java/net/minecraft/client/renderer/entity/RenderManager.java index d49ccbd8..d9728eb3 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderManager.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderManager.java @@ -114,7 +114,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderMinecart.java b/src/game/java/net/minecraft/client/renderer/entity/RenderMinecart.java index bb987826..9e107beb 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderMinecart.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderMinecart.java @@ -17,7 +17,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderMinecartMobSpawner.java b/src/game/java/net/minecraft/client/renderer/entity/RenderMinecartMobSpawner.java index 5ea2b6ed..33e04e08 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderMinecartMobSpawner.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderMinecartMobSpawner.java @@ -11,7 +11,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderMooshroom.java b/src/game/java/net/minecraft/client/renderer/entity/RenderMooshroom.java index 91b9487e..7c87baa0 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderMooshroom.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderMooshroom.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderOcelot.java b/src/game/java/net/minecraft/client/renderer/entity/RenderOcelot.java index 722b93e9..422fb827 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderOcelot.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderOcelot.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderPainting.java b/src/game/java/net/minecraft/client/renderer/entity/RenderPainting.java index 0d8ff5c0..ea95fbd2 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderPainting.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderPainting.java @@ -17,7 +17,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderPig.java b/src/game/java/net/minecraft/client/renderer/entity/RenderPig.java index 17ea1f5f..6a139273 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderPig.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderPig.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderPigZombie.java b/src/game/java/net/minecraft/client/renderer/entity/RenderPigZombie.java index ce297b4a..3c550cde 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderPigZombie.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderPigZombie.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderPlayer.java b/src/game/java/net/minecraft/client/renderer/entity/RenderPlayer.java index 73061c1e..361c75a3 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderPlayer.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderPlayer.java @@ -27,7 +27,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderPotion.java b/src/game/java/net/minecraft/client/renderer/entity/RenderPotion.java index 9efa9b19..35d99d96 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderPotion.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderPotion.java @@ -10,7 +10,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderRabbit.java b/src/game/java/net/minecraft/client/renderer/entity/RenderRabbit.java index 83828a57..de20ab22 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderRabbit.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderRabbit.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderSheep.java b/src/game/java/net/minecraft/client/renderer/entity/RenderSheep.java index 9360c29d..89e4d2d5 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderSheep.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderSheep.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderSilverfish.java b/src/game/java/net/minecraft/client/renderer/entity/RenderSilverfish.java index 7ecfeb8c..ca9f2084 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderSilverfish.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderSilverfish.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderSkeleton.java b/src/game/java/net/minecraft/client/renderer/entity/RenderSkeleton.java index ade5cd7e..cb35eeee 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderSkeleton.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderSkeleton.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderSlime.java b/src/game/java/net/minecraft/client/renderer/entity/RenderSlime.java index b9326119..b4c8056f 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderSlime.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderSlime.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderSnowMan.java b/src/game/java/net/minecraft/client/renderer/entity/RenderSnowMan.java index 61d0228e..a8303f0a 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderSnowMan.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderSnowMan.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderSnowball.java b/src/game/java/net/minecraft/client/renderer/entity/RenderSnowball.java index 2ae1077d..60c66adc 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderSnowball.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderSnowball.java @@ -16,7 +16,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderSpider.java b/src/game/java/net/minecraft/client/renderer/entity/RenderSpider.java index e8802498..ed2ae946 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderSpider.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderSpider.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderSquid.java b/src/game/java/net/minecraft/client/renderer/entity/RenderSquid.java index f780fee8..1e3afed9 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderSquid.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderSquid.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderTNTPrimed.java b/src/game/java/net/minecraft/client/renderer/entity/RenderTNTPrimed.java index 1eefdb11..eb695065 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderTNTPrimed.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderTNTPrimed.java @@ -18,7 +18,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderTntMinecart.java b/src/game/java/net/minecraft/client/renderer/entity/RenderTntMinecart.java index df08610c..a2afd900 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderTntMinecart.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderTntMinecart.java @@ -16,7 +16,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderVillager.java b/src/game/java/net/minecraft/client/renderer/entity/RenderVillager.java index 1482155b..e1b481c8 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderVillager.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderVillager.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderWitch.java b/src/game/java/net/minecraft/client/renderer/entity/RenderWitch.java index d4c38c54..f73750a6 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderWitch.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderWitch.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderWither.java b/src/game/java/net/minecraft/client/renderer/entity/RenderWither.java index a2a4931a..3f5b28e0 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderWither.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderWither.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderWolf.java b/src/game/java/net/minecraft/client/renderer/entity/RenderWolf.java index f3af8c0c..0c27ac61 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderWolf.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderWolf.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderXPOrb.java b/src/game/java/net/minecraft/client/renderer/entity/RenderXPOrb.java index 5544452b..4cc344ec 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderXPOrb.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderXPOrb.java @@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderZombie.java b/src/game/java/net/minecraft/client/renderer/entity/RenderZombie.java index e1fdda49..f918ca95 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderZombie.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderZombie.java @@ -21,7 +21,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/RendererLivingEntity.java b/src/game/java/net/minecraft/client/renderer/entity/RendererLivingEntity.java index cacb0d73..71428605 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RendererLivingEntity.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RendererLivingEntity.java @@ -43,7 +43,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerArmorBase.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerArmorBase.java index 3cb54455..46f5c1f6 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerArmorBase.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerArmorBase.java @@ -26,7 +26,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerArrow.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerArrow.java index a6c48669..8d0d446c 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerArrow.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerArrow.java @@ -16,7 +16,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerBipedArmor.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerBipedArmor.java index bab4fe4d..a0d5435c 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerBipedArmor.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerBipedArmor.java @@ -9,7 +9,7 @@ import net.minecraft.client.renderer.entity.RendererLivingEntity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCape.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCape.java index 24acabc9..55dfb413 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCape.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCape.java @@ -13,7 +13,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCreeperCharge.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCreeperCharge.java index 52e1510e..577d04dc 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCreeperCharge.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCreeperCharge.java @@ -18,7 +18,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCustomHead.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCustomHead.java index 1a616226..6aa00026 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCustomHead.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCustomHead.java @@ -27,7 +27,7 @@ import net.minecraft.util.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerDeadmau5Head.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerDeadmau5Head.java index 7edf020b..356f379c 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerDeadmau5Head.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerDeadmau5Head.java @@ -11,7 +11,7 @@ import net.minecraft.client.renderer.entity.RenderPlayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEnderDragonDeath.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEnderDragonDeath.java index f00d8d56..c7aee0e1 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEnderDragonDeath.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEnderDragonDeath.java @@ -22,7 +22,7 @@ import net.minecraft.entity.boss.EntityDragon; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEnderDragonEyes.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEnderDragonEyes.java index ae56bc41..7c538352 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEnderDragonEyes.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEnderDragonEyes.java @@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEndermanEyes.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEndermanEyes.java index 133b6de7..e8414030 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEndermanEyes.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEndermanEyes.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldBlock.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldBlock.java index 85c14647..a382ef83 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldBlock.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldBlock.java @@ -21,7 +21,7 @@ import net.minecraft.util.EnumWorldBlockLayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldItem.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldItem.java index 8df94a04..85245270 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldItem.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldItem.java @@ -19,7 +19,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldItemWitch.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldItemWitch.java index 2b283ae6..813733e2 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldItemWitch.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldItemWitch.java @@ -18,7 +18,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerIronGolemFlower.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerIronGolemFlower.java index 8e4c629b..4653f01b 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerIronGolemFlower.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerIronGolemFlower.java @@ -16,7 +16,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerMooshroomMushroom.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerMooshroomMushroom.java index 1d49dce4..d980f7ba 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerMooshroomMushroom.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerMooshroomMushroom.java @@ -18,7 +18,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerRenderer.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerRenderer.java index 00877da6..f42b6e0e 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerRenderer.java @@ -8,7 +8,7 @@ import net.minecraft.entity.EntityLivingBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSaddle.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSaddle.java index fe3defbb..384c8acb 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSaddle.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSaddle.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSheepWool.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSheepWool.java index 825c189b..346125ad 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSheepWool.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSheepWool.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSlimeGel.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSlimeGel.java index 0bb0646e..1f5ec4cb 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSlimeGel.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSlimeGel.java @@ -19,7 +19,7 @@ import net.minecraft.entity.monster.EntitySlime; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSnowmanHead.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSnowmanHead.java index b788ae51..703f215a 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSnowmanHead.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSnowmanHead.java @@ -14,7 +14,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSpiderEyes.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSpiderEyes.java index bb96111c..20c792e4 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSpiderEyes.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSpiderEyes.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerVillagerArmor.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerVillagerArmor.java index ea6e95e2..c66463a8 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerVillagerArmor.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerVillagerArmor.java @@ -9,7 +9,7 @@ import net.minecraft.client.renderer.entity.RendererLivingEntity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerWitherAura.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerWitherAura.java index dcb06c0b..04aad8d6 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerWitherAura.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerWitherAura.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerWolfCollar.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerWolfCollar.java index 0ee0cdff..4d11cebf 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerWolfCollar.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerWolfCollar.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/texture/AbstractTexture.java b/src/game/java/net/minecraft/client/renderer/texture/AbstractTexture.java index bbf818cf..b07aab46 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/AbstractTexture.java +++ b/src/game/java/net/minecraft/client/renderer/texture/AbstractTexture.java @@ -10,7 +10,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/texture/DynamicTexture.java b/src/game/java/net/minecraft/client/renderer/texture/DynamicTexture.java index eef82db1..aa9a0da0 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/DynamicTexture.java +++ b/src/game/java/net/minecraft/client/renderer/texture/DynamicTexture.java @@ -11,7 +11,7 @@ import net.minecraft.client.resources.IResourceManager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/texture/IIconCreator.java b/src/game/java/net/minecraft/client/renderer/texture/IIconCreator.java index 7a98366f..4be3a614 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/IIconCreator.java +++ b/src/game/java/net/minecraft/client/renderer/texture/IIconCreator.java @@ -6,7 +6,7 @@ package net.minecraft.client.renderer.texture; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/texture/ITextureObject.java b/src/game/java/net/minecraft/client/renderer/texture/ITextureObject.java index 66738f02..342a6983 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/ITextureObject.java +++ b/src/game/java/net/minecraft/client/renderer/texture/ITextureObject.java @@ -10,7 +10,7 @@ import net.minecraft.client.resources.IResourceManager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/texture/ITickable.java b/src/game/java/net/minecraft/client/renderer/texture/ITickable.java index 1840a624..d1c1de71 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/ITickable.java +++ b/src/game/java/net/minecraft/client/renderer/texture/ITickable.java @@ -6,7 +6,7 @@ package net.minecraft.client.renderer.texture; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/texture/ITickableTextureObject.java b/src/game/java/net/minecraft/client/renderer/texture/ITickableTextureObject.java index eb59abe4..0eabefbb 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/ITickableTextureObject.java +++ b/src/game/java/net/minecraft/client/renderer/texture/ITickableTextureObject.java @@ -6,7 +6,7 @@ package net.minecraft.client.renderer.texture; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/texture/LayeredColorMaskTexture.java b/src/game/java/net/minecraft/client/renderer/texture/LayeredColorMaskTexture.java index be9d2f67..c9666579 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/LayeredColorMaskTexture.java +++ b/src/game/java/net/minecraft/client/renderer/texture/LayeredColorMaskTexture.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/texture/LayeredTexture.java b/src/game/java/net/minecraft/client/renderer/texture/LayeredTexture.java index 03cfed5f..43c503a2 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/LayeredTexture.java +++ b/src/game/java/net/minecraft/client/renderer/texture/LayeredTexture.java @@ -18,7 +18,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/texture/SimpleTexture.java b/src/game/java/net/minecraft/client/renderer/texture/SimpleTexture.java index 0ff7d758..ff0bd25b 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/SimpleTexture.java +++ b/src/game/java/net/minecraft/client/renderer/texture/SimpleTexture.java @@ -17,7 +17,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/texture/Stitcher.java b/src/game/java/net/minecraft/client/renderer/texture/Stitcher.java index 020bc49a..217b2cfe 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/Stitcher.java +++ b/src/game/java/net/minecraft/client/renderer/texture/Stitcher.java @@ -20,7 +20,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/texture/TextureClock.java b/src/game/java/net/minecraft/client/renderer/texture/TextureClock.java index 9e9392f3..e5eda268 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/TextureClock.java +++ b/src/game/java/net/minecraft/client/renderer/texture/TextureClock.java @@ -11,7 +11,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/texture/TextureCompass.java b/src/game/java/net/minecraft/client/renderer/texture/TextureCompass.java index 3b7efc67..3f9c109c 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/TextureCompass.java +++ b/src/game/java/net/minecraft/client/renderer/texture/TextureCompass.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/texture/TextureManager.java b/src/game/java/net/minecraft/client/renderer/texture/TextureManager.java index f0558b58..91ef08aa 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/TextureManager.java +++ b/src/game/java/net/minecraft/client/renderer/texture/TextureManager.java @@ -8,6 +8,8 @@ import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.Callable; +import com.carrotsearch.hppc.ObjectIntHashMap; +import com.carrotsearch.hppc.ObjectIntMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -30,7 +32,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -48,7 +50,7 @@ public class TextureManager implements ITickable, IResourceManagerReloadListener private static final Logger logger = LogManager.getLogger(); private final Map mapTextureObjects = Maps.newHashMap(); private final List listTickables = Lists.newArrayList(); - private final Map mapTextureCounters = Maps.newHashMap(); + private final ObjectIntMap mapTextureCounters = new ObjectIntHashMap<>(); private IResourceManager theResourceManager; public TextureManager(IResourceManager resourceManager) { @@ -131,13 +133,7 @@ public class TextureManager implements ITickable, IResourceManagerReloadListener } public ResourceLocation getDynamicTextureLocation(String name, DynamicTexture texture) { - Integer integer = (Integer) this.mapTextureCounters.get(name); - if (integer == null) { - integer = Integer.valueOf(1); - } else { - integer = Integer.valueOf(integer.intValue() + 1); - } - + int integer = this.mapTextureCounters.getOrDefault(name, 0) + 1; this.mapTextureCounters.put(name, integer); ResourceLocation resourcelocation = new ResourceLocation( HString.format("dynamic/%s_%d", new Object[] { name, integer })); diff --git a/src/game/java/net/minecraft/client/renderer/texture/TextureMap.java b/src/game/java/net/minecraft/client/renderer/texture/TextureMap.java index 19973cc7..1466ea0a 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/TextureMap.java +++ b/src/game/java/net/minecraft/client/renderer/texture/TextureMap.java @@ -5,12 +5,13 @@ import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; import java.io.IOException; import java.util.Collection; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.Callable; +import com.carrotsearch.hppc.IntIndexedContainer; +import com.carrotsearch.hppc.cursors.IntCursor; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -44,7 +45,7 @@ import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -234,7 +235,7 @@ public class TextureMap extends AbstractTexture implements ITickableTextureObjec TextureMetadataSection texturemetadatasection = (TextureMetadataSection) iresource .getMetadata("texture"); if (texturemetadatasection != null) { - List list = texturemetadatasection.getListMipmaps(); + IntIndexedContainer list = texturemetadatasection.getListMipmaps(); if (!list.isEmpty()) { int l = abufferedimageColor[0].width; int i1 = abufferedimageColor[0].height; @@ -243,11 +244,8 @@ public class TextureMap extends AbstractTexture implements ITickableTextureObjec "Unable to load extra miplevels, source-texture is not power of two"); } } - - Iterator iterator = list.iterator(); - - while (iterator.hasNext()) { - int i2 = ((Integer) iterator.next()).intValue(); + for (IntCursor cur : list) { + int i2 = cur.value; if (i2 > 0 && i2 < abufferedimageColor.length - 1 && abufferedimageColor[i2] == null) { ResourceLocation resourcelocation2 = this.completeResourceLocation(resourcelocation, i2); @@ -319,7 +317,7 @@ public class TextureMap extends AbstractTexture implements ITickableTextureObjec TextureMetadataSection texturemetadatasection = (TextureMetadataSection) iresource .getMetadata("texture"); if (texturemetadatasection != null) { - List list = texturemetadatasection.getListMipmaps(); + IntIndexedContainer list = texturemetadatasection.getListMipmaps(); if (!list.isEmpty()) { int l = abufferedimage[0].width; int i1 = abufferedimage[0].height; @@ -329,10 +327,8 @@ public class TextureMap extends AbstractTexture implements ITickableTextureObjec } } - Iterator iterator = list.iterator(); - - while (iterator.hasNext()) { - int i2 = ((Integer) iterator.next()).intValue(); + for (IntCursor cur : list) { + int i2 = cur.value; if (i2 > 0 && i2 < abufferedimage.length - 1 && abufferedimage[i2] == null) { ResourceLocation resourcelocation2 = this.completeResourceLocation(resourcelocation, i2); diff --git a/src/game/java/net/minecraft/client/renderer/texture/TextureUtil.java b/src/game/java/net/minecraft/client/renderer/texture/TextureUtil.java index 8e868dd5..4be47c19 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/TextureUtil.java +++ b/src/game/java/net/minecraft/client/renderer/texture/TextureUtil.java @@ -23,7 +23,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/RenderEnderCrystal.java b/src/game/java/net/minecraft/client/renderer/tileentity/RenderEnderCrystal.java index 72069d6e..ad04c683 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/RenderEnderCrystal.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/RenderEnderCrystal.java @@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/RenderItemFrame.java b/src/game/java/net/minecraft/client/renderer/tileentity/RenderItemFrame.java index 5d1a2434..137db759 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/RenderItemFrame.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/RenderItemFrame.java @@ -37,7 +37,7 @@ import net.minecraft.world.storage.MapData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/RenderWitherSkull.java b/src/game/java/net/minecraft/client/renderer/tileentity/RenderWitherSkull.java index 82e0af2e..b6990e46 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/RenderWitherSkull.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/RenderWitherSkull.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityBannerRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityBannerRenderer.java index 7b704605..5e42bb63 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityBannerRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityBannerRenderer.java @@ -25,7 +25,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityBeaconRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityBeaconRenderer.java index d945d73c..383bf15d 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityBeaconRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityBeaconRenderer.java @@ -23,7 +23,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityChestRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityChestRenderer.java index 6b11a955..d393f474 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityChestRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityChestRenderer.java @@ -18,7 +18,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEnchantmentTableRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEnchantmentTableRenderer.java index a098c427..6eea8653 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEnchantmentTableRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEnchantmentTableRenderer.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEndPortalRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEndPortalRenderer.java index d19d81d0..c4f80d5e 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEndPortalRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEndPortalRenderer.java @@ -23,7 +23,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEnderChestRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEnderChestRenderer.java index 467f2b75..17f214ec 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEnderChestRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEnderChestRenderer.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityItemStackRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityItemStackRenderer.java index 3bc92571..6baeb7da 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityItemStackRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityItemStackRenderer.java @@ -22,7 +22,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityMobSpawnerRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityMobSpawnerRenderer.java index 98242adf..46a985c4 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityMobSpawnerRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityMobSpawnerRenderer.java @@ -12,7 +12,7 @@ import net.minecraft.tileentity.TileEntityMobSpawner; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityPistonRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityPistonRenderer.java index c891262a..f60d6517 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityPistonRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityPistonRenderer.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher.java index 438d17c2..5b6d7f53 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher.java @@ -33,7 +33,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySignRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySignRenderer.java index 205111fe..c745ed14 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySignRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySignRenderer.java @@ -26,7 +26,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySkullRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySkullRenderer.java index 23d6c009..cf1880d4 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySkullRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySkullRenderer.java @@ -20,7 +20,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySpecialRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySpecialRenderer.java index 946bc215..b8444099 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySpecialRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySpecialRenderer.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/renderer/vertex/DefaultVertexFormats.java b/src/game/java/net/minecraft/client/renderer/vertex/DefaultVertexFormats.java index f95aea21..4be8b2ac 100755 --- a/src/game/java/net/minecraft/client/renderer/vertex/DefaultVertexFormats.java +++ b/src/game/java/net/minecraft/client/renderer/vertex/DefaultVertexFormats.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.VertexFormat; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/AbstractResourcePack.java b/src/game/java/net/minecraft/client/resources/AbstractResourcePack.java index 2ff47ce0..67897f0d 100755 --- a/src/game/java/net/minecraft/client/resources/AbstractResourcePack.java +++ b/src/game/java/net/minecraft/client/resources/AbstractResourcePack.java @@ -24,7 +24,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/DefaultPlayerSkin.java b/src/game/java/net/minecraft/client/resources/DefaultPlayerSkin.java index 0a3b5850..da2c3d0d 100755 --- a/src/game/java/net/minecraft/client/resources/DefaultPlayerSkin.java +++ b/src/game/java/net/minecraft/client/resources/DefaultPlayerSkin.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/DefaultResourcePack.java b/src/game/java/net/minecraft/client/resources/DefaultResourcePack.java index 4a884832..962fb26c 100755 --- a/src/game/java/net/minecraft/client/resources/DefaultResourcePack.java +++ b/src/game/java/net/minecraft/client/resources/DefaultResourcePack.java @@ -20,7 +20,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/FallbackResourceManager.java b/src/game/java/net/minecraft/client/resources/FallbackResourceManager.java index 2de67bd8..1aeb0e9e 100755 --- a/src/game/java/net/minecraft/client/resources/FallbackResourceManager.java +++ b/src/game/java/net/minecraft/client/resources/FallbackResourceManager.java @@ -20,7 +20,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/FoliageColorReloadListener.java b/src/game/java/net/minecraft/client/resources/FoliageColorReloadListener.java index 65e12538..f602ffff 100755 --- a/src/game/java/net/minecraft/client/resources/FoliageColorReloadListener.java +++ b/src/game/java/net/minecraft/client/resources/FoliageColorReloadListener.java @@ -12,7 +12,7 @@ import net.minecraft.world.ColorizerFoliage; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/GrassColorReloadListener.java b/src/game/java/net/minecraft/client/resources/GrassColorReloadListener.java index 2cc8e524..2b4ce918 100755 --- a/src/game/java/net/minecraft/client/resources/GrassColorReloadListener.java +++ b/src/game/java/net/minecraft/client/resources/GrassColorReloadListener.java @@ -12,7 +12,7 @@ import net.minecraft.world.ColorizerGrass; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/I18n.java b/src/game/java/net/minecraft/client/resources/I18n.java index b47df8ef..47946269 100755 --- a/src/game/java/net/minecraft/client/resources/I18n.java +++ b/src/game/java/net/minecraft/client/resources/I18n.java @@ -6,7 +6,7 @@ package net.minecraft.client.resources; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/IReloadableResourceManager.java b/src/game/java/net/minecraft/client/resources/IReloadableResourceManager.java index 5f3deb6f..27360d19 100755 --- a/src/game/java/net/minecraft/client/resources/IReloadableResourceManager.java +++ b/src/game/java/net/minecraft/client/resources/IReloadableResourceManager.java @@ -8,7 +8,7 @@ import java.util.List; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/IResource.java b/src/game/java/net/minecraft/client/resources/IResource.java index 25d7684d..ebd696ed 100755 --- a/src/game/java/net/minecraft/client/resources/IResource.java +++ b/src/game/java/net/minecraft/client/resources/IResource.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/IResourceManager.java b/src/game/java/net/minecraft/client/resources/IResourceManager.java index 64ba7840..ccee41cc 100755 --- a/src/game/java/net/minecraft/client/resources/IResourceManager.java +++ b/src/game/java/net/minecraft/client/resources/IResourceManager.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/IResourceManagerReloadListener.java b/src/game/java/net/minecraft/client/resources/IResourceManagerReloadListener.java index bb3ca265..fdbd2bb5 100755 --- a/src/game/java/net/minecraft/client/resources/IResourceManagerReloadListener.java +++ b/src/game/java/net/minecraft/client/resources/IResourceManagerReloadListener.java @@ -6,7 +6,7 @@ package net.minecraft.client.resources; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/IResourcePack.java b/src/game/java/net/minecraft/client/resources/IResourcePack.java index fde05118..3d877940 100755 --- a/src/game/java/net/minecraft/client/resources/IResourcePack.java +++ b/src/game/java/net/minecraft/client/resources/IResourcePack.java @@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/Language.java b/src/game/java/net/minecraft/client/resources/Language.java index a2a2c9be..276f53ff 100755 --- a/src/game/java/net/minecraft/client/resources/Language.java +++ b/src/game/java/net/minecraft/client/resources/Language.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.HString; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/LanguageManager.java b/src/game/java/net/minecraft/client/resources/LanguageManager.java index 83eb33cc..59a34d61 100755 --- a/src/game/java/net/minecraft/client/resources/LanguageManager.java +++ b/src/game/java/net/minecraft/client/resources/LanguageManager.java @@ -22,7 +22,7 @@ import net.minecraft.util.StringTranslate; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/Locale.java b/src/game/java/net/minecraft/client/resources/Locale.java index bfef9b0e..318898a6 100755 --- a/src/game/java/net/minecraft/client/resources/Locale.java +++ b/src/game/java/net/minecraft/client/resources/Locale.java @@ -25,7 +25,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/ResourcePackFileNotFoundException.java b/src/game/java/net/minecraft/client/resources/ResourcePackFileNotFoundException.java index 5ced15e8..de878f0a 100755 --- a/src/game/java/net/minecraft/client/resources/ResourcePackFileNotFoundException.java +++ b/src/game/java/net/minecraft/client/resources/ResourcePackFileNotFoundException.java @@ -11,7 +11,7 @@ import net.lax1dude.eaglercraft.v1_8.HString; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/ResourcePackListEntry.java b/src/game/java/net/minecraft/client/resources/ResourcePackListEntry.java index e7d6dc98..b92ad177 100755 --- a/src/game/java/net/minecraft/client/resources/ResourcePackListEntry.java +++ b/src/game/java/net/minecraft/client/resources/ResourcePackListEntry.java @@ -22,7 +22,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/ResourcePackListEntryDefault.java b/src/game/java/net/minecraft/client/resources/ResourcePackListEntryDefault.java index 8adf9e3a..253c884e 100755 --- a/src/game/java/net/minecraft/client/resources/ResourcePackListEntryDefault.java +++ b/src/game/java/net/minecraft/client/resources/ResourcePackListEntryDefault.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/ResourcePackListEntryFound.java b/src/game/java/net/minecraft/client/resources/ResourcePackListEntryFound.java index 9399baff..ca10cca5 100755 --- a/src/game/java/net/minecraft/client/resources/ResourcePackListEntryFound.java +++ b/src/game/java/net/minecraft/client/resources/ResourcePackListEntryFound.java @@ -8,7 +8,7 @@ import net.minecraft.client.gui.GuiScreenResourcePacks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/ResourcePackRepository.java b/src/game/java/net/minecraft/client/resources/ResourcePackRepository.java index f8ce9f78..2950561f 100755 --- a/src/game/java/net/minecraft/client/resources/ResourcePackRepository.java +++ b/src/game/java/net/minecraft/client/resources/ResourcePackRepository.java @@ -30,7 +30,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/SimpleReloadableResourceManager.java b/src/game/java/net/minecraft/client/resources/SimpleReloadableResourceManager.java index ff4e31ea..a73d8438 100755 --- a/src/game/java/net/minecraft/client/resources/SimpleReloadableResourceManager.java +++ b/src/game/java/net/minecraft/client/resources/SimpleReloadableResourceManager.java @@ -24,7 +24,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/SimpleResource.java b/src/game/java/net/minecraft/client/resources/SimpleResource.java index 451f2221..1860a51a 100755 --- a/src/game/java/net/minecraft/client/resources/SimpleResource.java +++ b/src/game/java/net/minecraft/client/resources/SimpleResource.java @@ -21,7 +21,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/data/AnimationFrame.java b/src/game/java/net/minecraft/client/resources/data/AnimationFrame.java index fb714c76..2442b421 100755 --- a/src/game/java/net/minecraft/client/resources/data/AnimationFrame.java +++ b/src/game/java/net/minecraft/client/resources/data/AnimationFrame.java @@ -6,7 +6,7 @@ package net.minecraft.client.resources.data; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/data/AnimationMetadataSection.java b/src/game/java/net/minecraft/client/resources/data/AnimationMetadataSection.java index cfddc0a6..42824d66 100755 --- a/src/game/java/net/minecraft/client/resources/data/AnimationMetadataSection.java +++ b/src/game/java/net/minecraft/client/resources/data/AnimationMetadataSection.java @@ -1,10 +1,8 @@ package net.minecraft.client.resources.data; -import java.util.HashSet; import java.util.List; -import java.util.Set; - -import com.google.common.collect.Sets; +import com.carrotsearch.hppc.IntHashSet; +import com.carrotsearch.hppc.IntSet; /**+ * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. @@ -12,7 +10,7 @@ import com.google.common.collect.Sets; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -79,11 +77,11 @@ public class AnimationMetadataSection implements IMetadataSection { return ((AnimationFrame) this.animationFrames.get(parInt1)).getFrameIndex(); } - public Set getFrameIndexSet() { - HashSet hashset = Sets.newHashSet(); + public IntSet getFrameIndexSet() { + IntHashSet hashset = new IntHashSet(); for (int i = 0, l = this.animationFrames.size(); i < l; ++i) { - hashset.add(Integer.valueOf(this.animationFrames.get(i).getFrameIndex())); + hashset.add(this.animationFrames.get(i).getFrameIndex()); } return hashset; diff --git a/src/game/java/net/minecraft/client/resources/data/AnimationMetadataSectionSerializer.java b/src/game/java/net/minecraft/client/resources/data/AnimationMetadataSectionSerializer.java index b171ff5e..20247d2e 100755 --- a/src/game/java/net/minecraft/client/resources/data/AnimationMetadataSectionSerializer.java +++ b/src/game/java/net/minecraft/client/resources/data/AnimationMetadataSectionSerializer.java @@ -17,7 +17,7 @@ import net.lax1dude.eaglercraft.v1_8.json.JSONTypeSerializer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/data/BaseMetadataSectionSerializer.java b/src/game/java/net/minecraft/client/resources/data/BaseMetadataSectionSerializer.java index 466f8b6b..2a4fd52f 100755 --- a/src/game/java/net/minecraft/client/resources/data/BaseMetadataSectionSerializer.java +++ b/src/game/java/net/minecraft/client/resources/data/BaseMetadataSectionSerializer.java @@ -6,7 +6,7 @@ package net.minecraft.client.resources.data; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/data/FontMetadataSection.java b/src/game/java/net/minecraft/client/resources/data/FontMetadataSection.java index 4b0d095f..2ece17d7 100755 --- a/src/game/java/net/minecraft/client/resources/data/FontMetadataSection.java +++ b/src/game/java/net/minecraft/client/resources/data/FontMetadataSection.java @@ -6,7 +6,7 @@ package net.minecraft.client.resources.data; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/data/FontMetadataSectionSerializer.java b/src/game/java/net/minecraft/client/resources/data/FontMetadataSectionSerializer.java index d7c3504e..19944281 100755 --- a/src/game/java/net/minecraft/client/resources/data/FontMetadataSectionSerializer.java +++ b/src/game/java/net/minecraft/client/resources/data/FontMetadataSectionSerializer.java @@ -10,7 +10,7 @@ import org.json.JSONObject; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/data/IMetadataSection.java b/src/game/java/net/minecraft/client/resources/data/IMetadataSection.java index 96517805..93d24b86 100755 --- a/src/game/java/net/minecraft/client/resources/data/IMetadataSection.java +++ b/src/game/java/net/minecraft/client/resources/data/IMetadataSection.java @@ -6,7 +6,7 @@ package net.minecraft.client.resources.data; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/data/IMetadataSectionSerializer.java b/src/game/java/net/minecraft/client/resources/data/IMetadataSectionSerializer.java index 00e83560..fad00128 100755 --- a/src/game/java/net/minecraft/client/resources/data/IMetadataSectionSerializer.java +++ b/src/game/java/net/minecraft/client/resources/data/IMetadataSectionSerializer.java @@ -10,7 +10,7 @@ import net.lax1dude.eaglercraft.v1_8.json.JSONTypeDeserializer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/data/IMetadataSerializer.java b/src/game/java/net/minecraft/client/resources/data/IMetadataSerializer.java index 44c93031..510da561 100755 --- a/src/game/java/net/minecraft/client/resources/data/IMetadataSerializer.java +++ b/src/game/java/net/minecraft/client/resources/data/IMetadataSerializer.java @@ -12,7 +12,7 @@ import net.minecraft.util.RegistrySimple; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/data/LanguageMetadataSection.java b/src/game/java/net/minecraft/client/resources/data/LanguageMetadataSection.java index 460f7fd7..1c490b94 100755 --- a/src/game/java/net/minecraft/client/resources/data/LanguageMetadataSection.java +++ b/src/game/java/net/minecraft/client/resources/data/LanguageMetadataSection.java @@ -10,7 +10,7 @@ import net.minecraft.client.resources.Language; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/data/LanguageMetadataSectionSerializer.java b/src/game/java/net/minecraft/client/resources/data/LanguageMetadataSectionSerializer.java index e926da6d..cc9d855e 100755 --- a/src/game/java/net/minecraft/client/resources/data/LanguageMetadataSectionSerializer.java +++ b/src/game/java/net/minecraft/client/resources/data/LanguageMetadataSectionSerializer.java @@ -15,7 +15,7 @@ import net.minecraft.client.resources.Language; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/data/PackMetadataSection.java b/src/game/java/net/minecraft/client/resources/data/PackMetadataSection.java index 3601d8f6..0dbf8e61 100755 --- a/src/game/java/net/minecraft/client/resources/data/PackMetadataSection.java +++ b/src/game/java/net/minecraft/client/resources/data/PackMetadataSection.java @@ -8,7 +8,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/data/PackMetadataSectionSerializer.java b/src/game/java/net/minecraft/client/resources/data/PackMetadataSectionSerializer.java index b7f1904e..b9308764 100755 --- a/src/game/java/net/minecraft/client/resources/data/PackMetadataSectionSerializer.java +++ b/src/game/java/net/minecraft/client/resources/data/PackMetadataSectionSerializer.java @@ -13,7 +13,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/data/TextureMetadataSection.java b/src/game/java/net/minecraft/client/resources/data/TextureMetadataSection.java index 1dd12aed..14980924 100755 --- a/src/game/java/net/minecraft/client/resources/data/TextureMetadataSection.java +++ b/src/game/java/net/minecraft/client/resources/data/TextureMetadataSection.java @@ -1,7 +1,6 @@ package net.minecraft.client.resources.data; -import java.util.Collections; -import java.util.List; +import com.carrotsearch.hppc.IntIndexedContainer; /**+ * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. @@ -9,7 +8,7 @@ import java.util.List; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -26,9 +25,9 @@ import java.util.List; public class TextureMetadataSection implements IMetadataSection { private final boolean textureBlur; private final boolean textureClamp; - private final List listMipmaps; + private final IntIndexedContainer listMipmaps; - public TextureMetadataSection(boolean parFlag, boolean parFlag2, List parList) { + public TextureMetadataSection(boolean parFlag, boolean parFlag2, IntIndexedContainer parList) { this.textureBlur = parFlag; this.textureClamp = parFlag2; this.listMipmaps = parList; @@ -42,7 +41,7 @@ public class TextureMetadataSection implements IMetadataSection { return this.textureClamp; } - public List getListMipmaps() { - return Collections.unmodifiableList(this.listMipmaps); + public IntIndexedContainer getListMipmaps() { + return listMipmaps; } } \ No newline at end of file diff --git a/src/game/java/net/minecraft/client/resources/data/TextureMetadataSectionSerializer.java b/src/game/java/net/minecraft/client/resources/data/TextureMetadataSectionSerializer.java index 92bc8f83..22a0a1b3 100755 --- a/src/game/java/net/minecraft/client/resources/data/TextureMetadataSectionSerializer.java +++ b/src/game/java/net/minecraft/client/resources/data/TextureMetadataSectionSerializer.java @@ -1,12 +1,10 @@ package net.minecraft.client.resources.data; -import java.util.ArrayList; - import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import com.google.common.collect.Lists; +import com.carrotsearch.hppc.IntArrayList; /**+ * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. @@ -14,7 +12,7 @@ import com.google.common.collect.Lists; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -32,7 +30,7 @@ public class TextureMetadataSectionSerializer extends BaseMetadataSectionSeriali public TextureMetadataSection deserialize(JSONObject jsonobject) throws JSONException { boolean flag = jsonobject.optBoolean("blur", false); boolean flag1 = jsonobject.optBoolean("clamp", false); - ArrayList arraylist = Lists.newArrayList(); + IntArrayList arraylist = new IntArrayList(); if (jsonobject.has("mipmaps")) { try { JSONArray jsonarray = jsonobject.getJSONArray("mipmaps"); diff --git a/src/game/java/net/minecraft/client/resources/model/BuiltInModel.java b/src/game/java/net/minecraft/client/resources/model/BuiltInModel.java index 6570ab46..3b4b5b37 100755 --- a/src/game/java/net/minecraft/client/resources/model/BuiltInModel.java +++ b/src/game/java/net/minecraft/client/resources/model/BuiltInModel.java @@ -13,7 +13,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/model/IBakedModel.java b/src/game/java/net/minecraft/client/resources/model/IBakedModel.java index ebb29ee6..8f244e2d 100755 --- a/src/game/java/net/minecraft/client/resources/model/IBakedModel.java +++ b/src/game/java/net/minecraft/client/resources/model/IBakedModel.java @@ -13,7 +13,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/model/ModelBakery.java b/src/game/java/net/minecraft/client/resources/model/ModelBakery.java index 7c4e6197..a59bf8b4 100755 --- a/src/game/java/net/minecraft/client/resources/model/ModelBakery.java +++ b/src/game/java/net/minecraft/client/resources/model/ModelBakery.java @@ -54,7 +54,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -421,17 +421,17 @@ public class ModelBakery { if (deferred) { ModelBlock currentBlockModel = modelblock; ResourceLocation currentResourceLocation = modelblockdefinition$variant.getModelLocation(); - Integer blockId = null; + int blockId = -1; do { - blockId = BlockVertexIDs.modelToID.get(currentResourceLocation.toString()); - if (blockId != null) { + blockId = BlockVertexIDs.modelToID.getOrDefault(currentResourceLocation.toString(), -1); + if (blockId != -1) { break; } currentResourceLocation = currentBlockModel.getParentLocation(); currentBlockModel = models.get(currentResourceLocation); } while (currentBlockModel != null); - if (blockId != null) { - VertexMarkerState.markId = blockId.intValue(); + if (blockId != -1) { + VertexMarkerState.markId = blockId; try { weightedbakedmodel$builder.add( this.bakeModel(modelblock, modelblockdefinition$variant.getRotation(), diff --git a/src/game/java/net/minecraft/client/resources/model/ModelManager.java b/src/game/java/net/minecraft/client/resources/model/ModelManager.java index 74e87de4..470e5c79 100755 --- a/src/game/java/net/minecraft/client/resources/model/ModelManager.java +++ b/src/game/java/net/minecraft/client/resources/model/ModelManager.java @@ -12,7 +12,7 @@ import net.minecraft.util.IRegistry; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/model/ModelResourceLocation.java b/src/game/java/net/minecraft/client/resources/model/ModelResourceLocation.java index a5dc21f5..ca64c1dc 100755 --- a/src/game/java/net/minecraft/client/resources/model/ModelResourceLocation.java +++ b/src/game/java/net/minecraft/client/resources/model/ModelResourceLocation.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/model/ModelRotation.java b/src/game/java/net/minecraft/client/resources/model/ModelRotation.java index 79425357..0b9c36b3 100755 --- a/src/game/java/net/minecraft/client/resources/model/ModelRotation.java +++ b/src/game/java/net/minecraft/client/resources/model/ModelRotation.java @@ -1,8 +1,7 @@ package net.minecraft.client.resources.model; -import java.util.Map; - -import com.google.common.collect.Maps; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import net.lax1dude.eaglercraft.v1_8.vector.Matrix4f; import net.lax1dude.eaglercraft.v1_8.vector.Vector3f; @@ -15,7 +14,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -34,7 +33,7 @@ public enum ModelRotation { X90_Y270(90, 270), X180_Y0(180, 0), X180_Y90(180, 90), X180_Y180(180, 180), X180_Y270(180, 270), X270_Y0(270, 0), X270_Y90(270, 90), X270_Y180(270, 180), X270_Y270(270, 270); - private static final Map mapRotations = Maps.newHashMap(); + private static final IntObjectMap mapRotations = new IntObjectHashMap<>(); private final int combinedXY; private final Matrix4f matrix4d; private final int quartersX; @@ -98,14 +97,14 @@ public enum ModelRotation { } public static ModelRotation getModelRotation(int parInt1, int parInt2) { - return (ModelRotation) mapRotations.get(Integer - .valueOf(combineXY(MathHelper.normalizeAngle(parInt1, 360), MathHelper.normalizeAngle(parInt2, 360)))); + return mapRotations + .get(combineXY(MathHelper.normalizeAngle(parInt1, 360), MathHelper.normalizeAngle(parInt2, 360))); } static { ModelRotation[] lst = values(); for (int i = 0; i < lst.length; ++i) { - mapRotations.put(Integer.valueOf(lst[i].combinedXY), lst[i]); + mapRotations.put(lst[i].combinedXY, lst[i]); } } diff --git a/src/game/java/net/minecraft/client/resources/model/SimpleBakedModel.java b/src/game/java/net/minecraft/client/resources/model/SimpleBakedModel.java index f1dafc25..1c5b85de 100755 --- a/src/game/java/net/minecraft/client/resources/model/SimpleBakedModel.java +++ b/src/game/java/net/minecraft/client/resources/model/SimpleBakedModel.java @@ -17,7 +17,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/resources/model/WeightedBakedModel.java b/src/game/java/net/minecraft/client/resources/model/WeightedBakedModel.java index d90772a0..a6557de5 100755 --- a/src/game/java/net/minecraft/client/resources/model/WeightedBakedModel.java +++ b/src/game/java/net/minecraft/client/resources/model/WeightedBakedModel.java @@ -18,7 +18,7 @@ import net.minecraft.util.WeightedRandom; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/settings/GameSettings.java b/src/game/java/net/minecraft/client/settings/GameSettings.java index c3f4b971..e4114851 100755 --- a/src/game/java/net/minecraft/client/settings/GameSettings.java +++ b/src/game/java/net/minecraft/client/settings/GameSettings.java @@ -44,6 +44,7 @@ import net.minecraft.client.resources.I18n; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EnumPlayerModelParts; import net.minecraft.network.play.client.C15PacketClientSettings; +import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.MathHelper; import net.minecraft.world.EnumDifficulty; @@ -53,7 +54,7 @@ import net.minecraft.world.EnumDifficulty; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -660,6 +661,11 @@ public class GameSettings { * 100.0F) + "%") : "yee"))))))))))))); + } else if (EagRuntime.getPlatformType() != EnumPlatformType.DESKTOP + && parOptions == GameSettings.Options.EAGLER_VSYNC) { + boolean flag = this.getOptionOrdinalValue(parOptions); + return flag ? s + I18n.format("options.on", new Object[0]) + : EnumChatFormatting.RED + s + I18n.format("options.off", new Object[0]); } else if (parOptions.getEnumBoolean()) { boolean flag = this.getOptionOrdinalValue(parOptions); return flag ? s + I18n.format("options.on", new Object[0]) : s + I18n.format("options.off", new Object[0]); diff --git a/src/game/java/net/minecraft/client/settings/KeyBinding.java b/src/game/java/net/minecraft/client/settings/KeyBinding.java index e4b476ad..3c261635 100755 --- a/src/game/java/net/minecraft/client/settings/KeyBinding.java +++ b/src/game/java/net/minecraft/client/settings/KeyBinding.java @@ -3,11 +3,12 @@ package net.minecraft.client.settings; import java.util.List; import java.util.Set; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import net.minecraft.client.resources.I18n; -import net.minecraft.util.IntHashMap; /**+ * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. @@ -15,7 +16,7 @@ import net.minecraft.util.IntHashMap; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -31,7 +32,7 @@ import net.minecraft.util.IntHashMap; */ public class KeyBinding implements Comparable { private static final List keybindArray = Lists.newArrayList(); - private static final IntHashMap hash = new IntHashMap(); + private static final IntObjectMap hash = new IntObjectHashMap<>(); private static final Set keybindSet = Sets.newHashSet(); private final String keyDescription; private final int keyCodeDefault; @@ -42,7 +43,7 @@ public class KeyBinding implements Comparable { public static void onTick(int keyCode) { if (keyCode != 0) { - KeyBinding keybinding = (KeyBinding) hash.lookup(keyCode); + KeyBinding keybinding = hash.get(keyCode); if (keybinding != null) { ++keybinding.pressTime; } @@ -52,7 +53,7 @@ public class KeyBinding implements Comparable { public static void setKeyBindState(int keyCode, boolean pressed) { if (keyCode != 0) { - KeyBinding keybinding = (KeyBinding) hash.lookup(keyCode); + KeyBinding keybinding = hash.get(keyCode); if (keybinding != null) { keybinding.pressed = pressed; } @@ -68,11 +69,11 @@ public class KeyBinding implements Comparable { } public static void resetKeyBindingArrayAndHash() { - hash.clearMap(); + hash.clear(); for (int i = 0, l = keybindArray.size(); i < l; ++i) { KeyBinding keybinding = keybindArray.get(i); - hash.addKey(keybinding.keyCode, keybinding); + hash.put(keybinding.keyCode, keybinding); } } @@ -87,7 +88,7 @@ public class KeyBinding implements Comparable { this.keyCodeDefault = keyCode; this.keyCategory = category; keybindArray.add(this); - hash.addKey(keyCode, this); + hash.put(keyCode, this); keybindSet.add(category); } diff --git a/src/game/java/net/minecraft/client/stream/IStream.java b/src/game/java/net/minecraft/client/stream/IStream.java index cb9b3cf3..f8b4122b 100755 --- a/src/game/java/net/minecraft/client/stream/IStream.java +++ b/src/game/java/net/minecraft/client/stream/IStream.java @@ -6,7 +6,7 @@ package net.minecraft.client.stream; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/util/JsonBlendingMode.java b/src/game/java/net/minecraft/client/util/JsonBlendingMode.java index 45446e91..2330416d 100755 --- a/src/game/java/net/minecraft/client/util/JsonBlendingMode.java +++ b/src/game/java/net/minecraft/client/util/JsonBlendingMode.java @@ -11,7 +11,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/client/util/JsonException.java b/src/game/java/net/minecraft/client/util/JsonException.java index 03f871da..7f149d4f 100755 --- a/src/game/java/net/minecraft/client/util/JsonException.java +++ b/src/game/java/net/minecraft/client/util/JsonException.java @@ -14,7 +14,7 @@ import com.google.common.collect.Lists; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandBase.java b/src/game/java/net/minecraft/command/CommandBase.java index b5667f82..f5579f29 100755 --- a/src/game/java/net/minecraft/command/CommandBase.java +++ b/src/game/java/net/minecraft/command/CommandBase.java @@ -1,5 +1,7 @@ package net.minecraft.command; +import com.carrotsearch.hppc.ObjectContainer; +import com.carrotsearch.hppc.cursors.ObjectCursor; import com.google.common.base.Functions; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @@ -27,7 +29,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -597,6 +599,27 @@ public abstract class CommandBase implements ICommand { return arraylist; } + /**+ + * Returns a List of strings (chosen from the given strings) + * which the last word in the given string array is a + * beginning-match for. (Tab completion). + */ + public static List getListOfStringsMatchingLastWord(String[] parArrayOfString, + ObjectContainer parCollection) { + String s = parArrayOfString[parArrayOfString.length - 1]; + ArrayList arraylist = Lists.newArrayList(); + if (!parCollection.isEmpty()) { + for (ObjectCursor s1_ : parCollection) { + String s1 = s1_.value; + if (doesStringStartWith(s, s1)) { + arraylist.add(s1); + } + } + } + + return arraylist; + } + /**+ * Return whether the specified command parameter index is a * username parameter. diff --git a/src/game/java/net/minecraft/command/CommandBlockData.java b/src/game/java/net/minecraft/command/CommandBlockData.java index be0350df..386db7b9 100755 --- a/src/game/java/net/minecraft/command/CommandBlockData.java +++ b/src/game/java/net/minecraft/command/CommandBlockData.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandClearInventory.java b/src/game/java/net/minecraft/command/CommandClearInventory.java index 82bb4e86..e22eda55 100755 --- a/src/game/java/net/minecraft/command/CommandClearInventory.java +++ b/src/game/java/net/minecraft/command/CommandClearInventory.java @@ -16,7 +16,7 @@ import net.minecraft.util.ChatComponentTranslation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandClone.java b/src/game/java/net/minecraft/command/CommandClone.java index ddcaf082..355eeae8 100755 --- a/src/game/java/net/minecraft/command/CommandClone.java +++ b/src/game/java/net/minecraft/command/CommandClone.java @@ -21,7 +21,7 @@ import net.minecraft.world.gen.structure.StructureBoundingBox; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandCompare.java b/src/game/java/net/minecraft/command/CommandCompare.java index 2245b012..5bfb46ac 100755 --- a/src/game/java/net/minecraft/command/CommandCompare.java +++ b/src/game/java/net/minecraft/command/CommandCompare.java @@ -15,7 +15,7 @@ import net.minecraft.world.gen.structure.StructureBoundingBox; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandDefaultGameMode.java b/src/game/java/net/minecraft/command/CommandDefaultGameMode.java index fd750883..80a90fa9 100755 --- a/src/game/java/net/minecraft/command/CommandDefaultGameMode.java +++ b/src/game/java/net/minecraft/command/CommandDefaultGameMode.java @@ -13,7 +13,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandDifficulty.java b/src/game/java/net/minecraft/command/CommandDifficulty.java index f9027b5c..f9ffadc9 100755 --- a/src/game/java/net/minecraft/command/CommandDifficulty.java +++ b/src/game/java/net/minecraft/command/CommandDifficulty.java @@ -12,7 +12,7 @@ import net.minecraft.world.EnumDifficulty; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandEffect.java b/src/game/java/net/minecraft/command/CommandEffect.java index 80b70d48..aa72ee39 100755 --- a/src/game/java/net/minecraft/command/CommandEffect.java +++ b/src/game/java/net/minecraft/command/CommandEffect.java @@ -14,7 +14,7 @@ import net.minecraft.util.ChatComponentTranslation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandEnchant.java b/src/game/java/net/minecraft/command/CommandEnchant.java index 81fff5b8..d60100a7 100755 --- a/src/game/java/net/minecraft/command/CommandEnchant.java +++ b/src/game/java/net/minecraft/command/CommandEnchant.java @@ -14,7 +14,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandEntityData.java b/src/game/java/net/minecraft/command/CommandEntityData.java index 1c3c2147..c7412eaa 100755 --- a/src/game/java/net/minecraft/command/CommandEntityData.java +++ b/src/game/java/net/minecraft/command/CommandEntityData.java @@ -12,7 +12,7 @@ import net.minecraft.nbt.NBTTagCompound; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandException.java b/src/game/java/net/minecraft/command/CommandException.java index e9bcc37f..5d2281b8 100755 --- a/src/game/java/net/minecraft/command/CommandException.java +++ b/src/game/java/net/minecraft/command/CommandException.java @@ -6,7 +6,7 @@ package net.minecraft.command; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandExecuteAt.java b/src/game/java/net/minecraft/command/CommandExecuteAt.java index 850798ef..eb115166 100755 --- a/src/game/java/net/minecraft/command/CommandExecuteAt.java +++ b/src/game/java/net/minecraft/command/CommandExecuteAt.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandFill.java b/src/game/java/net/minecraft/command/CommandFill.java index 6efd36ae..b82a12da 100755 --- a/src/game/java/net/minecraft/command/CommandFill.java +++ b/src/game/java/net/minecraft/command/CommandFill.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandGameMode.java b/src/game/java/net/minecraft/command/CommandGameMode.java index 9d6048b9..36a750fe 100755 --- a/src/game/java/net/minecraft/command/CommandGameMode.java +++ b/src/game/java/net/minecraft/command/CommandGameMode.java @@ -13,7 +13,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandGameRule.java b/src/game/java/net/minecraft/command/CommandGameRule.java index f7168cf2..d1961004 100755 --- a/src/game/java/net/minecraft/command/CommandGameRule.java +++ b/src/game/java/net/minecraft/command/CommandGameRule.java @@ -14,7 +14,7 @@ import net.minecraft.world.GameRules; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandGive.java b/src/game/java/net/minecraft/command/CommandGive.java index dbc00870..c9c79ebf 100755 --- a/src/game/java/net/minecraft/command/CommandGive.java +++ b/src/game/java/net/minecraft/command/CommandGive.java @@ -16,7 +16,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandHandler.java b/src/game/java/net/minecraft/command/CommandHandler.java index 948192b6..6687b1be 100755 --- a/src/game/java/net/minecraft/command/CommandHandler.java +++ b/src/game/java/net/minecraft/command/CommandHandler.java @@ -21,7 +21,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandHelp.java b/src/game/java/net/minecraft/command/CommandHelp.java index 98d6d0b6..9825ef06 100755 --- a/src/game/java/net/minecraft/command/CommandHelp.java +++ b/src/game/java/net/minecraft/command/CommandHelp.java @@ -19,7 +19,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandKill.java b/src/game/java/net/minecraft/command/CommandKill.java index da568c36..33ba063e 100755 --- a/src/game/java/net/minecraft/command/CommandKill.java +++ b/src/game/java/net/minecraft/command/CommandKill.java @@ -12,7 +12,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandNotFoundException.java b/src/game/java/net/minecraft/command/CommandNotFoundException.java index b9b5ac80..13eafb09 100755 --- a/src/game/java/net/minecraft/command/CommandNotFoundException.java +++ b/src/game/java/net/minecraft/command/CommandNotFoundException.java @@ -6,7 +6,7 @@ package net.minecraft.command; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandParticle.java b/src/game/java/net/minecraft/command/CommandParticle.java index 9e7d3ad1..022784dc 100755 --- a/src/game/java/net/minecraft/command/CommandParticle.java +++ b/src/game/java/net/minecraft/command/CommandParticle.java @@ -13,7 +13,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandPlaySound.java b/src/game/java/net/minecraft/command/CommandPlaySound.java index fbee124b..b4263586 100755 --- a/src/game/java/net/minecraft/command/CommandPlaySound.java +++ b/src/game/java/net/minecraft/command/CommandPlaySound.java @@ -13,7 +13,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandReplaceItem.java b/src/game/java/net/minecraft/command/CommandReplaceItem.java index d174b70b..6a0a3356 100755 --- a/src/game/java/net/minecraft/command/CommandReplaceItem.java +++ b/src/game/java/net/minecraft/command/CommandReplaceItem.java @@ -1,8 +1,10 @@ package net.minecraft.command; -import com.google.common.collect.Maps; import java.util.List; -import java.util.Map; + +import com.carrotsearch.hppc.ObjectIntHashMap; +import com.carrotsearch.hppc.ObjectIntMap; + import net.minecraft.block.Block; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; @@ -23,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -39,7 +41,7 @@ import net.minecraft.world.World; */ public class CommandReplaceItem extends CommandBase { - private static final Map SHORTCUTS = Maps.newHashMap(); + private static final ObjectIntMap SHORTCUTS = new ObjectIntHashMap<>(); /**+ * Gets the name of the command @@ -169,7 +171,7 @@ public class CommandReplaceItem extends CommandBase { if (!SHORTCUTS.containsKey(shortcut)) { throw new CommandException("commands.generic.parameter.invalid", new Object[] { shortcut }); } else { - return ((Integer) SHORTCUTS.get(shortcut)).intValue(); + return SHORTCUTS.get(shortcut); } } @@ -189,7 +191,7 @@ public class CommandReplaceItem extends CommandBase { ? null : getListOfStringsMatchingLastWord(astring, Item.itemRegistry.getKeys())) - : getListOfStringsMatchingLastWord(astring, SHORTCUTS.keySet())))); + : getListOfStringsMatchingLastWord(astring, SHORTCUTS.keys())))); } protected String[] getUsernames() { @@ -206,36 +208,36 @@ public class CommandReplaceItem extends CommandBase { static { for (int i = 0; i < 54; ++i) { - SHORTCUTS.put("slot.container." + i, Integer.valueOf(i)); + SHORTCUTS.put("slot.container." + i, i); } for (int j = 0; j < 9; ++j) { - SHORTCUTS.put("slot.hotbar." + j, Integer.valueOf(j)); + SHORTCUTS.put("slot.hotbar." + j, j); } for (int k = 0; k < 27; ++k) { - SHORTCUTS.put("slot.inventory." + k, Integer.valueOf(9 + k)); + SHORTCUTS.put("slot.inventory." + k, 9 + k); } for (int l = 0; l < 27; ++l) { - SHORTCUTS.put("slot.enderchest." + l, Integer.valueOf(200 + l)); + SHORTCUTS.put("slot.enderchest." + l, 200 + l); } for (int i1 = 0; i1 < 8; ++i1) { - SHORTCUTS.put("slot.villager." + i1, Integer.valueOf(300 + i1)); + SHORTCUTS.put("slot.villager." + i1, 300 + i1); } for (int j1 = 0; j1 < 15; ++j1) { - SHORTCUTS.put("slot.horse." + j1, Integer.valueOf(500 + j1)); + SHORTCUTS.put("slot.horse." + j1, 500 + j1); } - SHORTCUTS.put("slot.weapon", Integer.valueOf(99)); - SHORTCUTS.put("slot.armor.head", Integer.valueOf(103)); - SHORTCUTS.put("slot.armor.chest", Integer.valueOf(102)); - SHORTCUTS.put("slot.armor.legs", Integer.valueOf(101)); - SHORTCUTS.put("slot.armor.feet", Integer.valueOf(100)); - SHORTCUTS.put("slot.horse.saddle", Integer.valueOf(400)); - SHORTCUTS.put("slot.horse.armor", Integer.valueOf(401)); - SHORTCUTS.put("slot.horse.chest", Integer.valueOf(499)); + SHORTCUTS.put("slot.weapon", 99); + SHORTCUTS.put("slot.armor.head", 103); + SHORTCUTS.put("slot.armor.chest", 102); + SHORTCUTS.put("slot.armor.legs", 101); + SHORTCUTS.put("slot.armor.feet", 100); + SHORTCUTS.put("slot.horse.saddle", 400); + SHORTCUTS.put("slot.horse.armor", 401); + SHORTCUTS.put("slot.horse.chest", 499); } } \ No newline at end of file diff --git a/src/game/java/net/minecraft/command/CommandResultStats.java b/src/game/java/net/minecraft/command/CommandResultStats.java index eba2055d..71cb3fa9 100755 --- a/src/game/java/net/minecraft/command/CommandResultStats.java +++ b/src/game/java/net/minecraft/command/CommandResultStats.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandServerKick.java b/src/game/java/net/minecraft/command/CommandServerKick.java index 3fb50f0a..9970da21 100755 --- a/src/game/java/net/minecraft/command/CommandServerKick.java +++ b/src/game/java/net/minecraft/command/CommandServerKick.java @@ -12,7 +12,7 @@ import net.minecraft.util.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandSetPlayerTimeout.java b/src/game/java/net/minecraft/command/CommandSetPlayerTimeout.java index 3bcf8d3e..434edb5d 100755 --- a/src/game/java/net/minecraft/command/CommandSetPlayerTimeout.java +++ b/src/game/java/net/minecraft/command/CommandSetPlayerTimeout.java @@ -8,7 +8,7 @@ import net.minecraft.server.MinecraftServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandSetSpawnpoint.java b/src/game/java/net/minecraft/command/CommandSetSpawnpoint.java index 148a71db..d16ff0c6 100755 --- a/src/game/java/net/minecraft/command/CommandSetSpawnpoint.java +++ b/src/game/java/net/minecraft/command/CommandSetSpawnpoint.java @@ -11,7 +11,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandShowSeed.java b/src/game/java/net/minecraft/command/CommandShowSeed.java index 24726888..7947ac73 100755 --- a/src/game/java/net/minecraft/command/CommandShowSeed.java +++ b/src/game/java/net/minecraft/command/CommandShowSeed.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandSpreadPlayers.java b/src/game/java/net/minecraft/command/CommandSpreadPlayers.java index d2099eda..437a1139 100755 --- a/src/game/java/net/minecraft/command/CommandSpreadPlayers.java +++ b/src/game/java/net/minecraft/command/CommandSpreadPlayers.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandStats.java b/src/game/java/net/minecraft/command/CommandStats.java index 2f73bb5d..fdd1b1f1 100755 --- a/src/game/java/net/minecraft/command/CommandStats.java +++ b/src/game/java/net/minecraft/command/CommandStats.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandTime.java b/src/game/java/net/minecraft/command/CommandTime.java index b0ebb08b..3e3b2d2f 100755 --- a/src/game/java/net/minecraft/command/CommandTime.java +++ b/src/game/java/net/minecraft/command/CommandTime.java @@ -11,7 +11,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandTitle.java b/src/game/java/net/minecraft/command/CommandTitle.java index e4bf88cc..937c5b2e 100755 --- a/src/game/java/net/minecraft/command/CommandTitle.java +++ b/src/game/java/net/minecraft/command/CommandTitle.java @@ -20,7 +20,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandToggleDownfall.java b/src/game/java/net/minecraft/command/CommandToggleDownfall.java index f3da57db..6928b969 100755 --- a/src/game/java/net/minecraft/command/CommandToggleDownfall.java +++ b/src/game/java/net/minecraft/command/CommandToggleDownfall.java @@ -9,7 +9,7 @@ import net.minecraft.world.storage.WorldInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandTrigger.java b/src/game/java/net/minecraft/command/CommandTrigger.java index e5ec1677..ca461816 100755 --- a/src/game/java/net/minecraft/command/CommandTrigger.java +++ b/src/game/java/net/minecraft/command/CommandTrigger.java @@ -18,7 +18,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandWeather.java b/src/game/java/net/minecraft/command/CommandWeather.java index 2d617d5a..0a1a8c2a 100755 --- a/src/game/java/net/minecraft/command/CommandWeather.java +++ b/src/game/java/net/minecraft/command/CommandWeather.java @@ -14,7 +14,7 @@ import net.minecraft.world.storage.WorldInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandWorldBorder.java b/src/game/java/net/minecraft/command/CommandWorldBorder.java index 6bedbd2c..cfa907b3 100755 --- a/src/game/java/net/minecraft/command/CommandWorldBorder.java +++ b/src/game/java/net/minecraft/command/CommandWorldBorder.java @@ -15,7 +15,7 @@ import net.minecraft.world.border.WorldBorder; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/CommandXP.java b/src/game/java/net/minecraft/command/CommandXP.java index 59b6f2be..08c735bb 100755 --- a/src/game/java/net/minecraft/command/CommandXP.java +++ b/src/game/java/net/minecraft/command/CommandXP.java @@ -11,7 +11,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/EntityNotFoundException.java b/src/game/java/net/minecraft/command/EntityNotFoundException.java index 6863f319..48c40452 100755 --- a/src/game/java/net/minecraft/command/EntityNotFoundException.java +++ b/src/game/java/net/minecraft/command/EntityNotFoundException.java @@ -6,7 +6,7 @@ package net.minecraft.command; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/IAdminCommand.java b/src/game/java/net/minecraft/command/IAdminCommand.java index 2773a97d..b6816689 100755 --- a/src/game/java/net/minecraft/command/IAdminCommand.java +++ b/src/game/java/net/minecraft/command/IAdminCommand.java @@ -6,7 +6,7 @@ package net.minecraft.command; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/ICommand.java b/src/game/java/net/minecraft/command/ICommand.java index b1bc237b..e23f3d84 100755 --- a/src/game/java/net/minecraft/command/ICommand.java +++ b/src/game/java/net/minecraft/command/ICommand.java @@ -9,7 +9,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/ICommandManager.java b/src/game/java/net/minecraft/command/ICommandManager.java index 41c77a3d..fca2a4c0 100755 --- a/src/game/java/net/minecraft/command/ICommandManager.java +++ b/src/game/java/net/minecraft/command/ICommandManager.java @@ -10,7 +10,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/ICommandSender.java b/src/game/java/net/minecraft/command/ICommandSender.java index 52758558..31efa535 100755 --- a/src/game/java/net/minecraft/command/ICommandSender.java +++ b/src/game/java/net/minecraft/command/ICommandSender.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/NumberInvalidException.java b/src/game/java/net/minecraft/command/NumberInvalidException.java index ee182d53..5c9eb55b 100755 --- a/src/game/java/net/minecraft/command/NumberInvalidException.java +++ b/src/game/java/net/minecraft/command/NumberInvalidException.java @@ -6,7 +6,7 @@ package net.minecraft.command; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/PlayerNotFoundException.java b/src/game/java/net/minecraft/command/PlayerNotFoundException.java index 9f1ee593..b87368ef 100755 --- a/src/game/java/net/minecraft/command/PlayerNotFoundException.java +++ b/src/game/java/net/minecraft/command/PlayerNotFoundException.java @@ -6,7 +6,7 @@ package net.minecraft.command; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/PlayerSelector.java b/src/game/java/net/minecraft/command/PlayerSelector.java index c5c6aa70..99d5d7ab 100755 --- a/src/game/java/net/minecraft/command/PlayerSelector.java +++ b/src/game/java/net/minecraft/command/PlayerSelector.java @@ -42,7 +42,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/ServerCommandManager.java b/src/game/java/net/minecraft/command/ServerCommandManager.java index 29497253..734c0103 100755 --- a/src/game/java/net/minecraft/command/ServerCommandManager.java +++ b/src/game/java/net/minecraft/command/ServerCommandManager.java @@ -29,7 +29,7 @@ import net.lax1dude.eaglercraft.v1_8.sp.server.ClientCommandDummy; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/SyntaxErrorException.java b/src/game/java/net/minecraft/command/SyntaxErrorException.java index d965d327..7d5228ff 100755 --- a/src/game/java/net/minecraft/command/SyntaxErrorException.java +++ b/src/game/java/net/minecraft/command/SyntaxErrorException.java @@ -6,7 +6,7 @@ package net.minecraft.command; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/WrongUsageException.java b/src/game/java/net/minecraft/command/WrongUsageException.java index e8d1e90a..2f34ce2c 100755 --- a/src/game/java/net/minecraft/command/WrongUsageException.java +++ b/src/game/java/net/minecraft/command/WrongUsageException.java @@ -6,7 +6,7 @@ package net.minecraft.command; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/server/CommandAchievement.java b/src/game/java/net/minecraft/command/server/CommandAchievement.java index 34ce6fdc..95e9eece 100755 --- a/src/game/java/net/minecraft/command/server/CommandAchievement.java +++ b/src/game/java/net/minecraft/command/server/CommandAchievement.java @@ -23,7 +23,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/server/CommandBlockLogic.java b/src/game/java/net/minecraft/command/server/CommandBlockLogic.java index 46bf6ae3..c8dee050 100755 --- a/src/game/java/net/minecraft/command/server/CommandBlockLogic.java +++ b/src/game/java/net/minecraft/command/server/CommandBlockLogic.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/server/CommandBroadcast.java b/src/game/java/net/minecraft/command/server/CommandBroadcast.java index d54f349d..34224f71 100755 --- a/src/game/java/net/minecraft/command/server/CommandBroadcast.java +++ b/src/game/java/net/minecraft/command/server/CommandBroadcast.java @@ -18,7 +18,7 @@ import net.minecraft.util.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/server/CommandEmote.java b/src/game/java/net/minecraft/command/server/CommandEmote.java index 6d55a2da..d363028e 100755 --- a/src/game/java/net/minecraft/command/server/CommandEmote.java +++ b/src/game/java/net/minecraft/command/server/CommandEmote.java @@ -19,7 +19,7 @@ import net.minecraft.util.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/server/CommandListPlayers.java b/src/game/java/net/minecraft/command/server/CommandListPlayers.java index 177cb579..6d8f1c64 100755 --- a/src/game/java/net/minecraft/command/server/CommandListPlayers.java +++ b/src/game/java/net/minecraft/command/server/CommandListPlayers.java @@ -14,7 +14,7 @@ import net.minecraft.util.ChatComponentTranslation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/server/CommandMessage.java b/src/game/java/net/minecraft/command/server/CommandMessage.java index a7b1ef71..b2860e27 100755 --- a/src/game/java/net/minecraft/command/server/CommandMessage.java +++ b/src/game/java/net/minecraft/command/server/CommandMessage.java @@ -23,7 +23,7 @@ import net.minecraft.util.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/server/CommandMessageRaw.java b/src/game/java/net/minecraft/command/server/CommandMessageRaw.java index e7ed145b..6650400b 100755 --- a/src/game/java/net/minecraft/command/server/CommandMessageRaw.java +++ b/src/game/java/net/minecraft/command/server/CommandMessageRaw.java @@ -22,7 +22,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/server/CommandScoreboard.java b/src/game/java/net/minecraft/command/server/CommandScoreboard.java index 8f6edd13..8c948698 100755 --- a/src/game/java/net/minecraft/command/server/CommandScoreboard.java +++ b/src/game/java/net/minecraft/command/server/CommandScoreboard.java @@ -39,7 +39,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/server/CommandSetBlock.java b/src/game/java/net/minecraft/command/server/CommandSetBlock.java index 92c0b993..a0f0097d 100755 --- a/src/game/java/net/minecraft/command/server/CommandSetBlock.java +++ b/src/game/java/net/minecraft/command/server/CommandSetBlock.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/server/CommandSetDefaultSpawnpoint.java b/src/game/java/net/minecraft/command/server/CommandSetDefaultSpawnpoint.java index da5864b1..a6fef594 100755 --- a/src/game/java/net/minecraft/command/server/CommandSetDefaultSpawnpoint.java +++ b/src/game/java/net/minecraft/command/server/CommandSetDefaultSpawnpoint.java @@ -15,7 +15,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/server/CommandSummon.java b/src/game/java/net/minecraft/command/server/CommandSummon.java index 63ec8d0d..1dcbc8d7 100755 --- a/src/game/java/net/minecraft/command/server/CommandSummon.java +++ b/src/game/java/net/minecraft/command/server/CommandSummon.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/server/CommandTeleport.java b/src/game/java/net/minecraft/command/server/CommandTeleport.java index 154d68d6..57b73cd3 100755 --- a/src/game/java/net/minecraft/command/server/CommandTeleport.java +++ b/src/game/java/net/minecraft/command/server/CommandTeleport.java @@ -19,7 +19,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/server/CommandTestFor.java b/src/game/java/net/minecraft/command/server/CommandTestFor.java index bfa56ba5..c7ca7307 100755 --- a/src/game/java/net/minecraft/command/server/CommandTestFor.java +++ b/src/game/java/net/minecraft/command/server/CommandTestFor.java @@ -19,7 +19,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/command/server/CommandTestForBlock.java b/src/game/java/net/minecraft/command/server/CommandTestForBlock.java index e8cc4086..67132b3f 100755 --- a/src/game/java/net/minecraft/command/server/CommandTestForBlock.java +++ b/src/game/java/net/minecraft/command/server/CommandTestForBlock.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/crash/CrashReport.java b/src/game/java/net/minecraft/crash/CrashReport.java index d455dee2..6d2e24b8 100755 --- a/src/game/java/net/minecraft/crash/CrashReport.java +++ b/src/game/java/net/minecraft/crash/CrashReport.java @@ -20,7 +20,7 @@ import net.minecraft.util.ReportedException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/crash/CrashReportCategory.java b/src/game/java/net/minecraft/crash/CrashReportCategory.java index 598c0bc0..4e79d445 100755 --- a/src/game/java/net/minecraft/crash/CrashReportCategory.java +++ b/src/game/java/net/minecraft/crash/CrashReportCategory.java @@ -17,7 +17,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/creativetab/CreativeTabs.java b/src/game/java/net/minecraft/creativetab/CreativeTabs.java index 08b76d67..267c3ce5 100755 --- a/src/game/java/net/minecraft/creativetab/CreativeTabs.java +++ b/src/game/java/net/minecraft/creativetab/CreativeTabs.java @@ -17,7 +17,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/dispenser/BehaviorDefaultDispenseItem.java b/src/game/java/net/minecraft/dispenser/BehaviorDefaultDispenseItem.java index fdbcd211..e35b22c9 100755 --- a/src/game/java/net/minecraft/dispenser/BehaviorDefaultDispenseItem.java +++ b/src/game/java/net/minecraft/dispenser/BehaviorDefaultDispenseItem.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/dispenser/BehaviorProjectileDispense.java b/src/game/java/net/minecraft/dispenser/BehaviorProjectileDispense.java index e28eb33b..e1743be4 100755 --- a/src/game/java/net/minecraft/dispenser/BehaviorProjectileDispense.java +++ b/src/game/java/net/minecraft/dispenser/BehaviorProjectileDispense.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/dispenser/IBehaviorDispenseItem.java b/src/game/java/net/minecraft/dispenser/IBehaviorDispenseItem.java index 1f69c682..e729edaf 100755 --- a/src/game/java/net/minecraft/dispenser/IBehaviorDispenseItem.java +++ b/src/game/java/net/minecraft/dispenser/IBehaviorDispenseItem.java @@ -8,7 +8,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/dispenser/IBlockSource.java b/src/game/java/net/minecraft/dispenser/IBlockSource.java index 817c3837..068acadf 100755 --- a/src/game/java/net/minecraft/dispenser/IBlockSource.java +++ b/src/game/java/net/minecraft/dispenser/IBlockSource.java @@ -9,7 +9,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/dispenser/ILocatableSource.java b/src/game/java/net/minecraft/dispenser/ILocatableSource.java index 9717651f..ad9b7acd 100755 --- a/src/game/java/net/minecraft/dispenser/ILocatableSource.java +++ b/src/game/java/net/minecraft/dispenser/ILocatableSource.java @@ -6,7 +6,7 @@ package net.minecraft.dispenser; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/dispenser/ILocation.java b/src/game/java/net/minecraft/dispenser/ILocation.java index 7d6dc6ca..6c2fb863 100755 --- a/src/game/java/net/minecraft/dispenser/ILocation.java +++ b/src/game/java/net/minecraft/dispenser/ILocation.java @@ -8,7 +8,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/dispenser/IPosition.java b/src/game/java/net/minecraft/dispenser/IPosition.java index b39c1bd3..32bd7e4f 100755 --- a/src/game/java/net/minecraft/dispenser/IPosition.java +++ b/src/game/java/net/minecraft/dispenser/IPosition.java @@ -6,7 +6,7 @@ package net.minecraft.dispenser; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/dispenser/PositionImpl.java b/src/game/java/net/minecraft/dispenser/PositionImpl.java index 7a8938bb..8070d180 100755 --- a/src/game/java/net/minecraft/dispenser/PositionImpl.java +++ b/src/game/java/net/minecraft/dispenser/PositionImpl.java @@ -6,7 +6,7 @@ package net.minecraft.dispenser; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/Enchantment.java b/src/game/java/net/minecraft/enchantment/Enchantment.java index ae13abf6..f5b47357 100755 --- a/src/game/java/net/minecraft/enchantment/Enchantment.java +++ b/src/game/java/net/minecraft/enchantment/Enchantment.java @@ -21,7 +21,7 @@ import net.minecraft.util.StatCollector; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentArrowDamage.java b/src/game/java/net/minecraft/enchantment/EnchantmentArrowDamage.java index fa1650fa..fb7241e0 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentArrowDamage.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentArrowDamage.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentArrowFire.java b/src/game/java/net/minecraft/enchantment/EnchantmentArrowFire.java index 1b091d34..5d4ed315 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentArrowFire.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentArrowFire.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentArrowInfinite.java b/src/game/java/net/minecraft/enchantment/EnchantmentArrowInfinite.java index ac172c77..6676c8f0 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentArrowInfinite.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentArrowInfinite.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentArrowKnockback.java b/src/game/java/net/minecraft/enchantment/EnchantmentArrowKnockback.java index bfd20396..cac1166f 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentArrowKnockback.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentArrowKnockback.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentDamage.java b/src/game/java/net/minecraft/enchantment/EnchantmentDamage.java index e7c5be49..5dd6c65e 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentDamage.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentDamage.java @@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentData.java b/src/game/java/net/minecraft/enchantment/EnchantmentData.java index 04b92d60..c0fdb509 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentData.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentData.java @@ -8,7 +8,7 @@ import net.minecraft.util.WeightedRandom; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentDigging.java b/src/game/java/net/minecraft/enchantment/EnchantmentDigging.java index 6d8bed94..3cf80a39 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentDigging.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentDigging.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentDurability.java b/src/game/java/net/minecraft/enchantment/EnchantmentDurability.java index 7d7ec62a..803c5e1f 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentDurability.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentDurability.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentFireAspect.java b/src/game/java/net/minecraft/enchantment/EnchantmentFireAspect.java index ec6d5f8c..b3fe0aa9 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentFireAspect.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentFireAspect.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentFishingSpeed.java b/src/game/java/net/minecraft/enchantment/EnchantmentFishingSpeed.java index 87d24190..58e3bfa9 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentFishingSpeed.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentFishingSpeed.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentHelper.java b/src/game/java/net/minecraft/enchantment/EnchantmentHelper.java index de7b02ae..0fa7db08 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentHelper.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentHelper.java @@ -3,11 +3,13 @@ package net.minecraft.enchantment; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; +import com.carrotsearch.hppc.IntIntHashMap; +import com.carrotsearch.hppc.IntIntMap; +import com.carrotsearch.hppc.cursors.IntCursor; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -29,7 +31,7 @@ import net.minecraft.util.WeightedRandom; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -85,15 +87,18 @@ public class EnchantmentHelper { } } - public static Map getEnchantments(ItemStack stack) { - LinkedHashMap linkedhashmap = Maps.newLinkedHashMap(); + /**+ + * Return the enchantments for the specified stack. + */ + public static IntIntMap getEnchantments(ItemStack stack) { + IntIntHashMap linkedhashmap = new IntIntHashMap(); NBTTagList nbttaglist = stack.getItem() == Items.enchanted_book ? Items.enchanted_book.getEnchantments(stack) : stack.getEnchantmentTagList(); if (nbttaglist != null) { for (int i = 0; i < nbttaglist.tagCount(); ++i) { short short1 = nbttaglist.getCompoundTagAt(i).getShort("id"); short short2 = nbttaglist.getCompoundTagAt(i).getShort("lvl"); - linkedhashmap.put(Integer.valueOf(short1), Integer.valueOf(short2)); + linkedhashmap.put(short1, short2); } } @@ -103,12 +108,11 @@ public class EnchantmentHelper { /**+ * Set the enchantments for the specified stack. */ - public static void setEnchantments(Map enchMap, ItemStack stack) { + public static void setEnchantments(IntIntMap enchMap, ItemStack stack) { NBTTagList nbttaglist = new NBTTagList(); - Iterator iterator = enchMap.keySet().iterator(); - while (iterator.hasNext()) { - int i = ((Integer) iterator.next()).intValue(); + for (IntCursor cur : enchMap.keys()) { + int i = cur.value; Enchantment enchantment = Enchantment.getEnchantmentById(i); if (enchantment != null) { NBTTagCompound nbttagcompound = new NBTTagCompound(); diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentKnockback.java b/src/game/java/net/minecraft/enchantment/EnchantmentKnockback.java index 66a175db..090779f6 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentKnockback.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentKnockback.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentLootBonus.java b/src/game/java/net/minecraft/enchantment/EnchantmentLootBonus.java index d46f0017..e7a2c32c 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentLootBonus.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentLootBonus.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentOxygen.java b/src/game/java/net/minecraft/enchantment/EnchantmentOxygen.java index 3cc270fb..14cc90e5 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentOxygen.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentOxygen.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentProtection.java b/src/game/java/net/minecraft/enchantment/EnchantmentProtection.java index 12637e07..4dfcd8ca 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentProtection.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentProtection.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentThorns.java b/src/game/java/net/minecraft/enchantment/EnchantmentThorns.java index 8f35b0fd..6dacc5db 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentThorns.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentThorns.java @@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentUntouching.java b/src/game/java/net/minecraft/enchantment/EnchantmentUntouching.java index 366de53a..cb7945c0 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentUntouching.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentUntouching.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentWaterWalker.java b/src/game/java/net/minecraft/enchantment/EnchantmentWaterWalker.java index 17cd2d7d..c2e7d65f 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentWaterWalker.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentWaterWalker.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentWaterWorker.java b/src/game/java/net/minecraft/enchantment/EnchantmentWaterWorker.java index ac6c7891..4aed4407 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentWaterWorker.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentWaterWorker.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/enchantment/EnumEnchantmentType.java b/src/game/java/net/minecraft/enchantment/EnumEnchantmentType.java index 7b986407..b2e7f162 100755 --- a/src/game/java/net/minecraft/enchantment/EnumEnchantmentType.java +++ b/src/game/java/net/minecraft/enchantment/EnumEnchantmentType.java @@ -13,7 +13,7 @@ import net.minecraft.item.ItemTool; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/DataWatcher.java b/src/game/java/net/minecraft/entity/DataWatcher.java index efa552a4..cfd09ac0 100755 --- a/src/game/java/net/minecraft/entity/DataWatcher.java +++ b/src/game/java/net/minecraft/entity/DataWatcher.java @@ -3,12 +3,15 @@ package net.minecraft.entity; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Map; import org.apache.commons.lang3.ObjectUtils; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; +import com.carrotsearch.hppc.ObjectIntHashMap; +import com.carrotsearch.hppc.ObjectIntMap; +import com.carrotsearch.hppc.cursors.ObjectCursor; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import net.minecraft.crash.CrashReport; import net.minecraft.crash.CrashReportCategory; @@ -24,7 +27,7 @@ import net.minecraft.util.Rotations; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -45,8 +48,8 @@ public class DataWatcher { * objects */ private boolean isBlank = true; - private static final Map, Integer> dataTypes = Maps.newHashMap(); - private final Map watchedObjects = Maps.newHashMap(); + private static final ObjectIntMap> dataTypes = new ObjectIntHashMap<>(); + private final IntObjectMap watchedObjects = new IntObjectHashMap<>(); private boolean objectChanged; public DataWatcher(Entity owner) { @@ -54,17 +57,17 @@ public class DataWatcher { } public void addObject(int id, T object) { - Integer integer = (Integer) dataTypes.get(object.getClass()); - if (integer == null) { + int integer = dataTypes.getOrDefault(object.getClass(), -1); + if (integer == -1) { throw new IllegalArgumentException("Unknown data type: " + object.getClass()); } else if (id > 31) { throw new IllegalArgumentException("Data value id is too big with " + id + "! (Max is " + 31 + ")"); - } else if (this.watchedObjects.containsKey(Integer.valueOf(id))) { + } else if (this.watchedObjects.containsKey(id)) { throw new IllegalArgumentException("Duplicate id value for " + id + "!"); } else { - DataWatcher.WatchableObject datawatcher$watchableobject = new DataWatcher.WatchableObject( - integer.intValue(), id, object); - this.watchedObjects.put(Integer.valueOf(id), datawatcher$watchableobject); + DataWatcher.WatchableObject datawatcher$watchableobject = new DataWatcher.WatchableObject(integer, id, + object); + this.watchedObjects.put(id, datawatcher$watchableobject); this.isBlank = false; } } @@ -76,7 +79,7 @@ public class DataWatcher { public void addObjectByDataType(int id, int type) { DataWatcher.WatchableObject datawatcher$watchableobject = new DataWatcher.WatchableObject(type, id, (Object) null); - this.watchedObjects.put(Integer.valueOf(id), datawatcher$watchableobject); + this.watchedObjects.put(id, datawatcher$watchableobject); this.isBlank = false; } @@ -122,7 +125,7 @@ public class DataWatcher { private DataWatcher.WatchableObject getWatchedObject(int id) { DataWatcher.WatchableObject datawatcher$watchableobject; try { - datawatcher$watchableobject = (DataWatcher.WatchableObject) this.watchedObjects.get(Integer.valueOf(id)); + datawatcher$watchableobject = (DataWatcher.WatchableObject) this.watchedObjects.get(id); } catch (Throwable throwable) { CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Getting synched entity data"); CrashReportCategory crashreportcategory = crashreport.makeCategory("Synched entity data"); @@ -178,7 +181,9 @@ public class DataWatcher { public List getChanged() { ArrayList arraylist = null; if (this.objectChanged) { - for (DataWatcher.WatchableObject datawatcher$watchableobject : this.watchedObjects.values()) { + for (ObjectCursor datawatcher$watchableobject_ : this.watchedObjects + .values()) { + DataWatcher.WatchableObject datawatcher$watchableobject = datawatcher$watchableobject_.value; if (datawatcher$watchableobject.isWatched()) { datawatcher$watchableobject.setWatched(false); if (arraylist == null) { @@ -195,8 +200,8 @@ public class DataWatcher { } public void writeTo(PacketBuffer buffer) throws IOException { - for (DataWatcher.WatchableObject datawatcher$watchableobject : this.watchedObjects.values()) { - writeWatchableObjectToPacketBuffer(buffer, datawatcher$watchableobject); + for (ObjectCursor datawatcher$watchableobject : this.watchedObjects.values()) { + writeWatchableObjectToPacketBuffer(buffer, datawatcher$watchableobject.value); } buffer.writeByte(127); } @@ -204,12 +209,12 @@ public class DataWatcher { public List getAllWatched() { ArrayList arraylist = null; - for (DataWatcher.WatchableObject datawatcher$watchableobject : this.watchedObjects.values()) { + for (ObjectCursor datawatcher$watchableobject : this.watchedObjects.values()) { if (arraylist == null) { arraylist = Lists.newArrayList(); } - arraylist.add(datawatcher$watchableobject); + arraylist.add(datawatcher$watchableobject.value); } return arraylist; @@ -319,7 +324,7 @@ public class DataWatcher { for (int i = 0, l = parList.size(); i < l; ++i) { DataWatcher.WatchableObject datawatcher$watchableobject = parList.get(i); DataWatcher.WatchableObject datawatcher$watchableobject1 = (DataWatcher.WatchableObject) this.watchedObjects - .get(Integer.valueOf(datawatcher$watchableobject.getDataValueId())); + .get(datawatcher$watchableobject.getDataValueId()); if (datawatcher$watchableobject1 != null) { datawatcher$watchableobject1.setObject(datawatcher$watchableobject.getObject()); this.owner.onDataWatcherUpdate(datawatcher$watchableobject.getDataValueId()); @@ -338,14 +343,14 @@ public class DataWatcher { } static { - dataTypes.put(Byte.class, Integer.valueOf(0)); - dataTypes.put(Short.class, Integer.valueOf(1)); - dataTypes.put(Integer.class, Integer.valueOf(2)); - dataTypes.put(Float.class, Integer.valueOf(3)); - dataTypes.put(String.class, Integer.valueOf(4)); - dataTypes.put(ItemStack.class, Integer.valueOf(5)); - dataTypes.put(BlockPos.class, Integer.valueOf(6)); - dataTypes.put(Rotations.class, Integer.valueOf(7)); + dataTypes.put(Byte.class, 0); + dataTypes.put(Short.class, 1); + dataTypes.put(Integer.class, 2); + dataTypes.put(Float.class, 3); + dataTypes.put(String.class, 4); + dataTypes.put(ItemStack.class, 5); + dataTypes.put(BlockPos.class, 6); + dataTypes.put(Rotations.class, 7); } public static class WatchableObject { diff --git a/src/game/java/net/minecraft/entity/Entity.java b/src/game/java/net/minecraft/entity/Entity.java index 7f425102..bf3ddbe2 100755 --- a/src/game/java/net/minecraft/entity/Entity.java +++ b/src/game/java/net/minecraft/entity/Entity.java @@ -61,7 +61,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/EntityAgeable.java b/src/game/java/net/minecraft/entity/EntityAgeable.java index e29afbf8..0d3f4d06 100755 --- a/src/game/java/net/minecraft/entity/EntityAgeable.java +++ b/src/game/java/net/minecraft/entity/EntityAgeable.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/EntityBodyHelper.java b/src/game/java/net/minecraft/entity/EntityBodyHelper.java index b09daf83..d5d26198 100755 --- a/src/game/java/net/minecraft/entity/EntityBodyHelper.java +++ b/src/game/java/net/minecraft/entity/EntityBodyHelper.java @@ -8,7 +8,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/EntityCreature.java b/src/game/java/net/minecraft/entity/EntityCreature.java index 1531d327..1e3b0fff 100755 --- a/src/game/java/net/minecraft/entity/EntityCreature.java +++ b/src/game/java/net/minecraft/entity/EntityCreature.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/EntityFlying.java b/src/game/java/net/minecraft/entity/EntityFlying.java index e924667c..86e2fbaf 100755 --- a/src/game/java/net/minecraft/entity/EntityFlying.java +++ b/src/game/java/net/minecraft/entity/EntityFlying.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/EntityHanging.java b/src/game/java/net/minecraft/entity/EntityHanging.java index ab3cee45..15cc291d 100755 --- a/src/game/java/net/minecraft/entity/EntityHanging.java +++ b/src/game/java/net/minecraft/entity/EntityHanging.java @@ -20,7 +20,7 @@ import org.apache.commons.lang3.Validate; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/EntityLeashKnot.java b/src/game/java/net/minecraft/entity/EntityLeashKnot.java index fcff343b..7bf9f3e3 100755 --- a/src/game/java/net/minecraft/entity/EntityLeashKnot.java +++ b/src/game/java/net/minecraft/entity/EntityLeashKnot.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/EntityList.java b/src/game/java/net/minecraft/entity/EntityList.java index 8e92fb0d..a5009a02 100755 --- a/src/game/java/net/minecraft/entity/EntityList.java +++ b/src/game/java/net/minecraft/entity/EntityList.java @@ -5,6 +5,10 @@ import java.util.List; import java.util.Map; import java.util.Set; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; +import com.carrotsearch.hppc.ObjectIntHashMap; +import com.carrotsearch.hppc.ObjectIntMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -86,7 +90,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -106,13 +110,19 @@ public class EntityList { private static final Map> stringToConstructorMapping = Maps .newHashMap(); private static final Map, String> classToStringMapping = Maps.newHashMap(); - private static final Map> idToClassMapping = Maps.newHashMap(); - private static final Map> idToConstructorMapping = Maps.newHashMap(); - private static final Map, Integer> classToIDMapping = Maps.newHashMap(); + private static final IntObjectMap> idToClassMapping = new IntObjectHashMap<>(); + private static final IntObjectMap> idToConstructorMapping = new IntObjectHashMap<>(); + private static final ObjectIntMap> classToIDMapping = new ObjectIntHashMap<>(); private static final Map, EntityConstructor> classToConstructorMapping = Maps .newHashMap(); - private static final Map stringToIDMapping = Maps.newHashMap(); - public static final Map entityEggs = Maps.newLinkedHashMap(); + /**+ + * provides a mapping between a string and an entity ID + */ + private static final ObjectIntMap stringToIDMapping = new ObjectIntHashMap<>(); + /**+ + * This is a HashMap of the Creative Entity Eggs/Spawners. + */ + public static final IntObjectMap entityEggs = new IntObjectHashMap<>(); /**+ * adds a mapping between Entity classes and both a string @@ -122,7 +132,7 @@ public class EntityList { EntityConstructor entityConstructor, String entityName, int id) { if (stringToClassMapping.containsKey(entityName)) { throw new IllegalArgumentException("ID is already registered: " + entityName); - } else if (idToClassMapping.containsKey(Integer.valueOf(id))) { + } else if (idToClassMapping.containsKey(id)) { throw new IllegalArgumentException("ID is already registered: " + id); } else if (id == 0) { throw new IllegalArgumentException("Cannot register to reserved id: " + id); @@ -132,11 +142,11 @@ public class EntityList { stringToClassMapping.put(entityName, entityClass); stringToConstructorMapping.put(entityName, entityConstructor); classToStringMapping.put(entityClass, entityName); - idToClassMapping.put(Integer.valueOf(id), entityClass); - idToConstructorMapping.put(Integer.valueOf(id), entityConstructor); - classToIDMapping.put(entityClass, Integer.valueOf(id)); + idToClassMapping.put(id, entityClass); + idToConstructorMapping.put(id, entityConstructor); + classToIDMapping.put(entityClass, id); classToConstructorMapping.put(entityClass, entityConstructor); - stringToIDMapping.put(entityName, Integer.valueOf(id)); + stringToIDMapping.put(entityName, id); } } @@ -148,7 +158,7 @@ public class EntityList { EntityConstructor entityConstructor, String entityName, int entityID, int baseColor, int spotColor) { addMapping(entityClass, entityConstructor, entityName, entityID); - entityEggs.put(Integer.valueOf(entityID), new EntityList.EntityEggInfo(entityID, baseColor, spotColor)); + entityEggs.put(entityID, new EntityList.EntityEggInfo(entityID, baseColor, spotColor)); } /**+ @@ -248,31 +258,31 @@ public class EntityList { * gets the entityID of a specific entity */ public static int getEntityID(Entity entityIn) { - Integer integer = (Integer) classToIDMapping.get(entityIn.getClass()); - return integer == null ? 0 : integer.intValue(); + int integer = classToIDMapping.getOrDefault(entityIn.getClass(), -1); + return integer == -1 ? 0 : integer; } public static Class getClassFromID(int entityID) { - return (Class) idToClassMapping.get(Integer.valueOf(entityID)); + return idToClassMapping.get(entityID); } public static EntityConstructor getConstructorFromID(int entityID) { - return idToConstructorMapping.get(Integer.valueOf(entityID)); + return idToConstructorMapping.get(entityID); } /**+ * Gets the string representation of a specific entity. */ public static String getEntityString(Entity entityIn) { - return (String) classToStringMapping.get(entityIn.getClass()); + return classToStringMapping.get(entityIn.getClass()); } /**+ * Returns the ID assigned to it's string representation */ public static int getIDFromString(String entityName) { - Integer integer = (Integer) stringToIDMapping.get(entityName); - return integer == null ? 90 : integer.intValue(); + int integer = stringToIDMapping.getOrDefault(entityName, -1); + return integer == -1 ? 90 : integer; } /**+ @@ -280,7 +290,7 @@ public class EntityList { * classToStringMapping */ public static String getStringFromID(int entityID) { - return (String) classToStringMapping.get(getClassFromID(entityID)); + return classToStringMapping.get(getClassFromID(entityID)); } public static void func_151514_a() { diff --git a/src/game/java/net/minecraft/entity/EntityLiving.java b/src/game/java/net/minecraft/entity/EntityLiving.java index d4647ee1..c77ecffe 100755 --- a/src/game/java/net/minecraft/entity/EntityLiving.java +++ b/src/game/java/net/minecraft/entity/EntityLiving.java @@ -44,7 +44,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/EntityLivingBase.java b/src/game/java/net/minecraft/entity/EntityLivingBase.java index b97a83b4..8988067f 100755 --- a/src/game/java/net/minecraft/entity/EntityLivingBase.java +++ b/src/game/java/net/minecraft/entity/EntityLivingBase.java @@ -1,13 +1,14 @@ package net.minecraft.entity; +import com.carrotsearch.hppc.IntArrayList; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; +import com.carrotsearch.hppc.ObjectContainer; +import com.carrotsearch.hppc.cursors.IntObjectCursor; +import com.carrotsearch.hppc.cursors.ObjectCursor; import com.google.common.base.Predicate; import com.google.common.base.Predicates; -import com.google.common.collect.Maps; - -import java.util.Collection; -import java.util.Iterator; import java.util.List; -import java.util.Map; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; import net.minecraft.block.Block; @@ -59,7 +60,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -80,7 +81,7 @@ public abstract class EntityLivingBase extends Entity { sprintingSpeedBoostModifierUUID, "Sprinting speed boost", 0.30000001192092896D, 2)).setSaved(false); private BaseAttributeMap attributeMap; private final CombatTracker _combatTracker = new CombatTracker(this); - private final Map activePotionsMap = Maps.newHashMap(); + private final IntObjectMap activePotionsMap = new IntObjectHashMap<>(); /**+ * The equipment this mob was previously wearing, used for * syncing. @@ -448,8 +449,8 @@ public abstract class EntityLivingBase extends Entity { if (!this.activePotionsMap.isEmpty()) { NBTTagList nbttaglist = new NBTTagList(); - for (PotionEffect potioneffect : this.activePotionsMap.values()) { - nbttaglist.appendTag(potioneffect.writeCustomPotionEffectToNBT(new NBTTagCompound())); + for (ObjectCursor potioneffect : this.activePotionsMap.values()) { + nbttaglist.appendTag(potioneffect.value.writeCustomPotionEffectToNBT(new NBTTagCompound())); } nbttagcompound.setTag("ActiveEffects", nbttaglist); @@ -474,7 +475,7 @@ public abstract class EntityLivingBase extends Entity { NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i); PotionEffect potioneffect = PotionEffect.readCustomPotionEffectFromNBT(nbttagcompound1); if (potioneffect != null) { - this.activePotionsMap.put(Integer.valueOf(potioneffect.getPotionID()), potioneffect); + this.activePotionsMap.put(potioneffect.getPotionID(), potioneffect); } } } @@ -498,14 +499,16 @@ public abstract class EntityLivingBase extends Entity { } protected void updatePotionEffects() { - Iterator iterator = this.activePotionsMap.keySet().iterator(); + IntArrayList deadPotionEffects = null; - while (iterator.hasNext()) { - Integer integer = (Integer) iterator.next(); - PotionEffect potioneffect = (PotionEffect) this.activePotionsMap.get(integer); + for (IntObjectCursor cur : this.activePotionsMap) { + int integer = cur.key; + PotionEffect potioneffect = cur.value; if (!potioneffect.onUpdate(this)) { if (!this.worldObj.isRemote) { - iterator.remove(); + if (deadPotionEffects == null) + deadPotionEffects = new IntArrayList(4); + deadPotionEffects.add(integer); this.onFinishedPotionEffect(potioneffect); } } else if (potioneffect.getDuration() % 600 == 0) { @@ -513,6 +516,10 @@ public abstract class EntityLivingBase extends Entity { } } + if (deadPotionEffects != null) { + this.activePotionsMap.removeAll(deadPotionEffects); + } + if (this.potionsNeedUpdate) { if (!this.worldObj.isRemote) { this.updatePotionMetadata(); @@ -558,9 +565,9 @@ public abstract class EntityLivingBase extends Entity { this.resetPotionEffectMetadata(); this.setInvisible(false); } else { - int i = PotionHelper.calcPotionLiquidColor(this.activePotionsMap.values()); - this.dataWatcher.updateObject(8, - Byte.valueOf((byte) (PotionHelper.getAreAmbient(this.activePotionsMap.values()) ? 1 : 0))); + ObjectContainer cc = this.activePotionsMap.values(); + int i = PotionHelper.calcPotionLiquidColor(cc); + this.dataWatcher.updateObject(8, Byte.valueOf((byte) (PotionHelper.getAreAmbient(cc) ? 1 : 0))); this.dataWatcher.updateObject(7, Integer.valueOf(i)); this.setInvisible(this.isPotionActive(Potion.invisibility.id)); } @@ -576,29 +583,28 @@ public abstract class EntityLivingBase extends Entity { } public void clearActivePotions() { - Iterator iterator = this.activePotionsMap.keySet().iterator(); - - while (iterator.hasNext()) { - Integer integer = (Integer) iterator.next(); - PotionEffect potioneffect = (PotionEffect) this.activePotionsMap.get(integer); + for (ObjectCursor cur : activePotionsMap.values()) { + PotionEffect potioneffect = cur.value; if (!this.worldObj.isRemote) { - iterator.remove(); this.onFinishedPotionEffect(potioneffect); } } + if (!this.worldObj.isRemote) { + activePotionsMap.clear(); + } } - public Collection getActivePotionEffects() { + public ObjectContainer getActivePotionEffects() { return this.activePotionsMap.values(); } public boolean isPotionActive(int potionId) { - return this.activePotionsMap.containsKey(Integer.valueOf(potionId)); + return this.activePotionsMap.containsKey(potionId); } public boolean isPotionActive(Potion potionIn) { - return this.activePotionsMap.containsKey(Integer.valueOf(potionIn.id)); + return this.activePotionsMap.containsKey(potionIn.id); } /**+ @@ -606,7 +612,7 @@ public abstract class EntityLivingBase extends Entity { * active, null otherwise. */ public PotionEffect getActivePotionEffect(Potion potionIn) { - return (PotionEffect) this.activePotionsMap.get(Integer.valueOf(potionIn.id)); + return this.activePotionsMap.get(potionIn.id); } /**+ @@ -614,13 +620,11 @@ public abstract class EntityLivingBase extends Entity { */ public void addPotionEffect(PotionEffect potioneffectIn) { if (this.isPotionApplicable(potioneffectIn)) { - if (this.activePotionsMap.containsKey(Integer.valueOf(potioneffectIn.getPotionID()))) { - ((PotionEffect) this.activePotionsMap.get(Integer.valueOf(potioneffectIn.getPotionID()))) - .combine(potioneffectIn); - this.onChangedPotionEffect( - (PotionEffect) this.activePotionsMap.get(Integer.valueOf(potioneffectIn.getPotionID())), true); + if (this.activePotionsMap.containsKey(potioneffectIn.getPotionID())) { + this.activePotionsMap.get(potioneffectIn.getPotionID()).combine(potioneffectIn); + this.onChangedPotionEffect(this.activePotionsMap.get(potioneffectIn.getPotionID()), true); } else { - this.activePotionsMap.put(Integer.valueOf(potioneffectIn.getPotionID()), potioneffectIn); + this.activePotionsMap.put(potioneffectIn.getPotionID(), potioneffectIn); this.onNewPotionEffect(potioneffectIn); } @@ -649,14 +653,14 @@ public abstract class EntityLivingBase extends Entity { * Remove the speified potion effect from this entity. */ public void removePotionEffectClient(int potionId) { - this.activePotionsMap.remove(Integer.valueOf(potionId)); + this.activePotionsMap.remove(potionId); } /**+ * Remove the specified potion effect from this entity. */ public void removePotionEffect(int potionId) { - PotionEffect potioneffect = (PotionEffect) this.activePotionsMap.remove(Integer.valueOf(potionId)); + PotionEffect potioneffect = this.activePotionsMap.remove(potionId); if (potioneffect != null) { this.onFinishedPotionEffect(potioneffect); } diff --git a/src/game/java/net/minecraft/entity/EntityMinecartCommandBlock.java b/src/game/java/net/minecraft/entity/EntityMinecartCommandBlock.java index 51bae457..d6c2dba0 100755 --- a/src/game/java/net/minecraft/entity/EntityMinecartCommandBlock.java +++ b/src/game/java/net/minecraft/entity/EntityMinecartCommandBlock.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/EntitySpawnPlacementRegistry.java b/src/game/java/net/minecraft/entity/EntitySpawnPlacementRegistry.java index 8a59a7a4..ba70a210 100755 --- a/src/game/java/net/minecraft/entity/EntitySpawnPlacementRegistry.java +++ b/src/game/java/net/minecraft/entity/EntitySpawnPlacementRegistry.java @@ -43,7 +43,7 @@ import net.minecraft.entity.passive.EntityWolf; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/EntityTracker.java b/src/game/java/net/minecraft/entity/EntityTracker.java index f4d0cc62..a153d491 100755 --- a/src/game/java/net/minecraft/entity/EntityTracker.java +++ b/src/game/java/net/minecraft/entity/EntityTracker.java @@ -1,5 +1,7 @@ package net.minecraft.entity; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import java.util.ArrayList; @@ -33,7 +35,6 @@ import net.minecraft.entity.projectile.EntityPotion; import net.minecraft.entity.projectile.EntitySmallFireball; import net.minecraft.entity.projectile.EntitySnowball; import net.minecraft.network.Packet; -import net.minecraft.util.IntHashMap; import net.minecraft.util.ReportedException; import net.minecraft.world.WorldServer; import net.minecraft.world.chunk.Chunk; @@ -46,7 +47,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -71,7 +72,7 @@ public class EntityTracker { /**+ * Used for identity lookup of tracked entities. */ - private IntHashMap trackedEntityHashTable = new IntHashMap(); + private IntObjectMap trackedEntityHashTable = new IntObjectHashMap<>(); private int maxTrackingDistanceThreshold; public EntityTracker(WorldServer theWorldIn) { @@ -80,6 +81,10 @@ public class EntityTracker { .getEntityViewDistance(); } + public void updateMaxTrackingThreshold(int dist) { + maxTrackingDistanceThreshold = dist; + } + public void trackEntity(Entity parEntity) { if (parEntity instanceof EntityPlayerMP) { this.trackEntity(parEntity, 512, 2); @@ -87,7 +92,7 @@ public class EntityTracker { for (EntityTrackerEntry entitytrackerentry : this.trackedEntities) { if (entitytrackerentry.trackedEntity != entityplayermp) { - entitytrackerentry.updatePlayerEntity(entityplayermp); + entitytrackerentry.updatePlayerEntity(entityplayermp, maxTrackingDistanceThreshold); } } } else if (parEntity instanceof EntityFishHook) { @@ -154,20 +159,16 @@ public class EntityTracker { */ public void addEntityToTracker(Entity entityIn, int trackingRange, final int updateFrequency, boolean sendVelocityUpdates) { - if (trackingRange > this.maxTrackingDistanceThreshold) { - trackingRange = this.maxTrackingDistanceThreshold; - } - try { - if (this.trackedEntityHashTable.containsItem(entityIn.getEntityId())) { + if (this.trackedEntityHashTable.containsKey(entityIn.getEntityId())) { throw new IllegalStateException("Entity is already tracked!"); } EntityTrackerEntry entitytrackerentry = new EntityTrackerEntry(entityIn, trackingRange, updateFrequency, sendVelocityUpdates); this.trackedEntities.add(entitytrackerentry); - this.trackedEntityHashTable.addKey(entityIn.getEntityId(), entitytrackerentry); - entitytrackerentry.updatePlayerEntities(this.theWorld.playerEntities); + this.trackedEntityHashTable.put(entityIn.getEntityId(), entitytrackerentry); + entitytrackerentry.updatePlayerEntities(this.theWorld.playerEntities, maxTrackingDistanceThreshold); } catch (Throwable throwable) { CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Adding entity to track"); CrashReportCategory crashreportcategory = crashreport.makeCategory("Entity To Track"); @@ -184,7 +185,7 @@ public class EntityTracker { }); entityIn.addEntityCrashInfo(crashreportcategory); CrashReportCategory crashreportcategory1 = crashreport.makeCategory("Entity That Is Already Tracked"); - ((EntityTrackerEntry) this.trackedEntityHashTable.lookup(entityIn.getEntityId())).trackedEntity + this.trackedEntityHashTable.get(entityIn.getEntityId()).trackedEntity .addEntityCrashInfo(crashreportcategory1); try { @@ -205,8 +206,7 @@ public class EntityTracker { } } - EntityTrackerEntry entitytrackerentry1 = (EntityTrackerEntry) this.trackedEntityHashTable - .removeObject(entityIn.getEntityId()); + EntityTrackerEntry entitytrackerentry1 = this.trackedEntityHashTable.remove(entityIn.getEntityId()); if (entitytrackerentry1 != null) { this.trackedEntities.remove(entitytrackerentry1); entitytrackerentry1.sendDestroyEntityPacketToTrackedPlayers(); @@ -218,7 +218,7 @@ public class EntityTracker { ArrayList arraylist = Lists.newArrayList(); for (EntityTrackerEntry entitytrackerentry : this.trackedEntities) { - entitytrackerentry.updatePlayerList(this.theWorld.playerEntities); + entitytrackerentry.updatePlayerList(this.theWorld.playerEntities, maxTrackingDistanceThreshold); if (entitytrackerentry.playerEntitiesUpdated && entitytrackerentry.trackedEntity instanceof EntityPlayerMP) { arraylist.add((EntityPlayerMP) entitytrackerentry.trackedEntity); @@ -230,7 +230,7 @@ public class EntityTracker { for (EntityTrackerEntry entitytrackerentry1 : this.trackedEntities) { if (entitytrackerentry1.trackedEntity != entityplayermp) { - entitytrackerentry1.updatePlayerEntity(entityplayermp); + entitytrackerentry1.updatePlayerEntity(entityplayermp, maxTrackingDistanceThreshold); } } } @@ -240,17 +240,16 @@ public class EntityTracker { public void func_180245_a(EntityPlayerMP parEntityPlayerMP) { for (EntityTrackerEntry entitytrackerentry : this.trackedEntities) { if (entitytrackerentry.trackedEntity == parEntityPlayerMP) { - entitytrackerentry.updatePlayerEntities(this.theWorld.playerEntities); + entitytrackerentry.updatePlayerEntities(this.theWorld.playerEntities, maxTrackingDistanceThreshold); } else { - entitytrackerentry.updatePlayerEntity(parEntityPlayerMP); + entitytrackerentry.updatePlayerEntity(parEntityPlayerMP, maxTrackingDistanceThreshold); } } } public void sendToAllTrackingEntity(Entity entityIn, Packet parPacket) { - EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) this.trackedEntityHashTable - .lookup(entityIn.getEntityId()); + EntityTrackerEntry entitytrackerentry = this.trackedEntityHashTable.get(entityIn.getEntityId()); if (entitytrackerentry != null) { entitytrackerentry.sendPacketToTrackedPlayers(parPacket); } @@ -258,8 +257,7 @@ public class EntityTracker { } public void func_151248_b(Entity entityIn, Packet parPacket) { - EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) this.trackedEntityHashTable - .lookup(entityIn.getEntityId()); + EntityTrackerEntry entitytrackerentry = this.trackedEntityHashTable.get(entityIn.getEntityId()); if (entitytrackerentry != null) { entitytrackerentry.func_151261_b(parPacket); } @@ -278,7 +276,7 @@ public class EntityTracker { if (entitytrackerentry.trackedEntity != parEntityPlayerMP && entitytrackerentry.trackedEntity.chunkCoordX == parChunk.xPosition && entitytrackerentry.trackedEntity.chunkCoordZ == parChunk.zPosition) { - entitytrackerentry.updatePlayerEntity(parEntityPlayerMP); + entitytrackerentry.updatePlayerEntity(parEntityPlayerMP, maxTrackingDistanceThreshold); } } diff --git a/src/game/java/net/minecraft/entity/EntityTrackerEntry.java b/src/game/java/net/minecraft/entity/EntityTrackerEntry.java index dd7e2cc2..33b37247 100755 --- a/src/game/java/net/minecraft/entity/EntityTrackerEntry.java +++ b/src/game/java/net/minecraft/entity/EntityTrackerEntry.java @@ -1,5 +1,6 @@ package net.minecraft.entity; +import com.carrotsearch.hppc.cursors.ObjectCursor; import com.google.common.collect.Sets; import java.util.Collection; import java.util.List; @@ -65,7 +66,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -135,7 +136,7 @@ public class EntityTrackerEntry { return this.trackedEntity.getEntityId(); } - public void updatePlayerList(List parList) { + public void updatePlayerList(List parList, int trackingDistanceMax) { this.playerEntitiesUpdated = false; if (!this.firstUpdateDone || this.trackedEntity.getDistanceSq(this.lastTrackedEntityPosX, this.lastTrackedEntityPosY, this.lastTrackedEntityPosZ) > 16.0D) { @@ -144,7 +145,7 @@ public class EntityTrackerEntry { this.lastTrackedEntityPosZ = this.trackedEntity.posZ; this.firstUpdateDone = true; this.playerEntitiesUpdated = true; - this.updatePlayerEntities(parList); + this.updatePlayerEntities(parList, trackingDistanceMax); } if (this.field_85178_v != this.trackedEntity.ridingEntity @@ -341,9 +342,9 @@ public class EntityTrackerEntry { } - public void updatePlayerEntity(EntityPlayerMP playerMP) { + public void updatePlayerEntity(EntityPlayerMP playerMP, int trackingDistanceMax) { if (playerMP != this.trackedEntity) { - if (this.func_180233_c(playerMP)) { + if (this.func_180233_c(playerMP, trackingDistanceMax)) { if (!this.trackingPlayers.contains(playerMP) && (this.isPlayerWatchingThisChunk(playerMP) || this.trackedEntity.forceSpawn)) { this.trackingPlayers.add(playerMP); @@ -408,12 +409,17 @@ public class EntityTrackerEntry { } } + this.lastHeadMotion = MathHelper + .floor_float(this.trackedEntity.getRotationYawHead() * 256.0F / 360.0F); + playerMP.playerNetServerHandler + .sendPacket(new S19PacketEntityHeadLook(this.trackedEntity, (byte) lastHeadMotion)); + if (this.trackedEntity instanceof EntityLivingBase) { EntityLivingBase entitylivingbase = (EntityLivingBase) this.trackedEntity; - for (PotionEffect potioneffect : entitylivingbase.getActivePotionEffects()) { + for (ObjectCursor potioneffect : entitylivingbase.getActivePotionEffects()) { playerMP.playerNetServerHandler.sendPacket( - new S1DPacketEntityEffect(this.trackedEntity.getEntityId(), potioneffect)); + new S1DPacketEntityEffect(this.trackedEntity.getEntityId(), potioneffect.value)); } } } @@ -425,11 +431,11 @@ public class EntityTrackerEntry { } } - public boolean func_180233_c(EntityPlayerMP playerMP) { + public boolean func_180233_c(EntityPlayerMP playerMP, int trackingDistanceMax) { + int i = trackingDistanceThreshold > trackingDistanceMax ? trackingDistanceMax : trackingDistanceThreshold; double d0 = playerMP.posX - (double) (this.encodedPosX / 32); double d1 = playerMP.posZ - (double) (this.encodedPosZ / 32); - return d0 >= (double) (-this.trackingDistanceThreshold) && d0 <= (double) this.trackingDistanceThreshold - && d1 >= (double) (-this.trackingDistanceThreshold) && d1 <= (double) this.trackingDistanceThreshold + return d0 >= (double) (-i) && d0 <= (double) i && d1 >= (double) (-i) && d1 <= (double) i && this.trackedEntity.isSpectatedByPlayer(playerMP); } @@ -438,9 +444,9 @@ public class EntityTrackerEntry { this.trackedEntity.chunkCoordX, this.trackedEntity.chunkCoordZ); } - public void updatePlayerEntities(List parList) { + public void updatePlayerEntities(List parList, int trackingDistanceMax) { for (int i = 0; i < parList.size(); ++i) { - this.updatePlayerEntity((EntityPlayerMP) parList.get(i)); + this.updatePlayerEntity((EntityPlayerMP) parList.get(i), trackingDistanceMax); } } diff --git a/src/game/java/net/minecraft/entity/EnumCreatureAttribute.java b/src/game/java/net/minecraft/entity/EnumCreatureAttribute.java index 16d86954..d223cfec 100755 --- a/src/game/java/net/minecraft/entity/EnumCreatureAttribute.java +++ b/src/game/java/net/minecraft/entity/EnumCreatureAttribute.java @@ -6,7 +6,7 @@ package net.minecraft.entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/EnumCreatureType.java b/src/game/java/net/minecraft/entity/EnumCreatureType.java index 37f92b69..02d17815 100755 --- a/src/game/java/net/minecraft/entity/EnumCreatureType.java +++ b/src/game/java/net/minecraft/entity/EnumCreatureType.java @@ -13,7 +13,7 @@ import net.minecraft.entity.passive.IAnimals; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/IEntityLivingData.java b/src/game/java/net/minecraft/entity/IEntityLivingData.java index e3996e76..5777e28c 100755 --- a/src/game/java/net/minecraft/entity/IEntityLivingData.java +++ b/src/game/java/net/minecraft/entity/IEntityLivingData.java @@ -6,7 +6,7 @@ package net.minecraft.entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/IEntityMultiPart.java b/src/game/java/net/minecraft/entity/IEntityMultiPart.java index 98f6450c..1b4e90c8 100755 --- a/src/game/java/net/minecraft/entity/IEntityMultiPart.java +++ b/src/game/java/net/minecraft/entity/IEntityMultiPart.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/IEntityOwnable.java b/src/game/java/net/minecraft/entity/IEntityOwnable.java index 33d5e5c9..53de9986 100755 --- a/src/game/java/net/minecraft/entity/IEntityOwnable.java +++ b/src/game/java/net/minecraft/entity/IEntityOwnable.java @@ -6,7 +6,7 @@ package net.minecraft.entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/IMerchant.java b/src/game/java/net/minecraft/entity/IMerchant.java index 06572465..7fb2fd39 100755 --- a/src/game/java/net/minecraft/entity/IMerchant.java +++ b/src/game/java/net/minecraft/entity/IMerchant.java @@ -12,7 +12,7 @@ import net.minecraft.village.MerchantRecipeList; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/INpc.java b/src/game/java/net/minecraft/entity/INpc.java index 48f64e07..42541f0b 100755 --- a/src/game/java/net/minecraft/entity/INpc.java +++ b/src/game/java/net/minecraft/entity/INpc.java @@ -8,7 +8,7 @@ import net.minecraft.entity.passive.IAnimals; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/IProjectile.java b/src/game/java/net/minecraft/entity/IProjectile.java index d5253c33..36ef7045 100755 --- a/src/game/java/net/minecraft/entity/IProjectile.java +++ b/src/game/java/net/minecraft/entity/IProjectile.java @@ -6,7 +6,7 @@ package net.minecraft.entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/IRangedAttackMob.java b/src/game/java/net/minecraft/entity/IRangedAttackMob.java index 32f8d215..1a6533bb 100755 --- a/src/game/java/net/minecraft/entity/IRangedAttackMob.java +++ b/src/game/java/net/minecraft/entity/IRangedAttackMob.java @@ -6,7 +6,7 @@ package net.minecraft.entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/NpcMerchant.java b/src/game/java/net/minecraft/entity/NpcMerchant.java index f3405bcd..0bea600d 100755 --- a/src/game/java/net/minecraft/entity/NpcMerchant.java +++ b/src/game/java/net/minecraft/entity/NpcMerchant.java @@ -14,7 +14,7 @@ import net.minecraft.village.MerchantRecipeList; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/SharedMonsterAttributes.java b/src/game/java/net/minecraft/entity/SharedMonsterAttributes.java index 8271e78a..f7faed50 100755 --- a/src/game/java/net/minecraft/entity/SharedMonsterAttributes.java +++ b/src/game/java/net/minecraft/entity/SharedMonsterAttributes.java @@ -19,7 +19,7 @@ import net.minecraft.nbt.NBTTagList; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIArrowAttack.java b/src/game/java/net/minecraft/entity/ai/EntityAIArrowAttack.java index f23ac1d5..91257053 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIArrowAttack.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIArrowAttack.java @@ -11,7 +11,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIAttackOnCollide.java b/src/game/java/net/minecraft/entity/ai/EntityAIAttackOnCollide.java index 97a8b0ea..b1f4e28a 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIAttackOnCollide.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIAttackOnCollide.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIAvoidEntity.java b/src/game/java/net/minecraft/entity/ai/EntityAIAvoidEntity.java index 67950828..cdb4665b 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIAvoidEntity.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIAvoidEntity.java @@ -16,7 +16,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIBase.java b/src/game/java/net/minecraft/entity/ai/EntityAIBase.java index d9f6c2c5..5c478093 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIBase.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIBase.java @@ -6,7 +6,7 @@ package net.minecraft.entity.ai; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIBeg.java b/src/game/java/net/minecraft/entity/ai/EntityAIBeg.java index df94cc69..56188a19 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIBeg.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIBeg.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIBreakDoor.java b/src/game/java/net/minecraft/entity/ai/EntityAIBreakDoor.java index 80ba3a65..5ebba8ed 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIBreakDoor.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIBreakDoor.java @@ -11,7 +11,7 @@ import net.minecraft.world.EnumDifficulty; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIControlledByPlayer.java b/src/game/java/net/minecraft/entity/ai/EntityAIControlledByPlayer.java index 1e128497..73e07c25 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIControlledByPlayer.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIControlledByPlayer.java @@ -19,7 +19,7 @@ import net.minecraft.world.pathfinder.WalkNodeProcessor; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAICreeperSwell.java b/src/game/java/net/minecraft/entity/ai/EntityAICreeperSwell.java index d9f01f16..a72daef1 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAICreeperSwell.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAICreeperSwell.java @@ -9,7 +9,7 @@ import net.minecraft.entity.monster.EntityCreeper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIDefendVillage.java b/src/game/java/net/minecraft/entity/ai/EntityAIDefendVillage.java index adb084f2..da0e4396 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIDefendVillage.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIDefendVillage.java @@ -11,7 +11,7 @@ import net.minecraft.village.Village; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIDoorInteract.java b/src/game/java/net/minecraft/entity/ai/EntityAIDoorInteract.java index a5c72684..0e749ece 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIDoorInteract.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIDoorInteract.java @@ -15,7 +15,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIEatGrass.java b/src/game/java/net/minecraft/entity/ai/EntityAIEatGrass.java index 0bf054c5..1b788577 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIEatGrass.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIEatGrass.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIFindEntityNearest.java b/src/game/java/net/minecraft/entity/ai/EntityAIFindEntityNearest.java index 3b8dc468..6d2a6a53 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIFindEntityNearest.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIFindEntityNearest.java @@ -18,7 +18,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIFindEntityNearestPlayer.java b/src/game/java/net/minecraft/entity/ai/EntityAIFindEntityNearestPlayer.java index b43b52f7..9d7ff921 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIFindEntityNearestPlayer.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIFindEntityNearestPlayer.java @@ -21,7 +21,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIFleeSun.java b/src/game/java/net/minecraft/entity/ai/EntityAIFleeSun.java index b0c51b14..184ba855 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIFleeSun.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIFleeSun.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIFollowGolem.java b/src/game/java/net/minecraft/entity/ai/EntityAIFollowGolem.java index b4e6877b..2cabd798 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIFollowGolem.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIFollowGolem.java @@ -10,7 +10,7 @@ import net.minecraft.entity.passive.EntityVillager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIFollowOwner.java b/src/game/java/net/minecraft/entity/ai/EntityAIFollowOwner.java index 07f06604..242d8569 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIFollowOwner.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIFollowOwner.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIFollowParent.java b/src/game/java/net/minecraft/entity/ai/EntityAIFollowParent.java index 7b990e05..2dfe6858 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIFollowParent.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIFollowParent.java @@ -9,7 +9,7 @@ import net.minecraft.entity.passive.EntityAnimal; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIHarvestFarmland.java b/src/game/java/net/minecraft/entity/ai/EntityAIHarvestFarmland.java index d6bb164d..29bada5f 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIHarvestFarmland.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIHarvestFarmland.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIHurtByTarget.java b/src/game/java/net/minecraft/entity/ai/EntityAIHurtByTarget.java index 2498cb7b..9ea86428 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIHurtByTarget.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIHurtByTarget.java @@ -12,7 +12,7 @@ import net.minecraft.util.AxisAlignedBB; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAILeapAtTarget.java b/src/game/java/net/minecraft/entity/ai/EntityAILeapAtTarget.java index 695cdd83..f965a743 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAILeapAtTarget.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAILeapAtTarget.java @@ -10,7 +10,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAILookAtTradePlayer.java b/src/game/java/net/minecraft/entity/ai/EntityAILookAtTradePlayer.java index ed60bde1..02465619 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAILookAtTradePlayer.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAILookAtTradePlayer.java @@ -9,7 +9,7 @@ import net.minecraft.entity.player.EntityPlayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAILookAtVillager.java b/src/game/java/net/minecraft/entity/ai/EntityAILookAtVillager.java index d68ab45b..8a8c4d8e 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAILookAtVillager.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAILookAtVillager.java @@ -9,7 +9,7 @@ import net.minecraft.entity.passive.EntityVillager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAILookIdle.java b/src/game/java/net/minecraft/entity/ai/EntityAILookIdle.java index 6ffd0511..528df41f 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAILookIdle.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAILookIdle.java @@ -8,7 +8,7 @@ import net.minecraft.entity.EntityLiving; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIMate.java b/src/game/java/net/minecraft/entity/ai/EntityAIMate.java index 8b85b0e5..94bc9b2e 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIMate.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIMate.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIMoveIndoors.java b/src/game/java/net/minecraft/entity/ai/EntityAIMoveIndoors.java index b55d695d..8d4da2d9 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIMoveIndoors.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIMoveIndoors.java @@ -12,7 +12,7 @@ import net.minecraft.village.VillageDoorInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIMoveThroughVillage.java b/src/game/java/net/minecraft/entity/ai/EntityAIMoveThroughVillage.java index 1fe2dc9b..842e2aad 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIMoveThroughVillage.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIMoveThroughVillage.java @@ -17,7 +17,7 @@ import net.minecraft.village.VillageDoorInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIMoveToBlock.java b/src/game/java/net/minecraft/entity/ai/EntityAIMoveToBlock.java index 5c4555bd..10e9ec62 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIMoveToBlock.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIMoveToBlock.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIMoveTowardsRestriction.java b/src/game/java/net/minecraft/entity/ai/EntityAIMoveTowardsRestriction.java index 5060779c..4a0749b6 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIMoveTowardsRestriction.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIMoveTowardsRestriction.java @@ -10,7 +10,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIMoveTowardsTarget.java b/src/game/java/net/minecraft/entity/ai/EntityAIMoveTowardsTarget.java index 7687d5c0..66df2221 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIMoveTowardsTarget.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIMoveTowardsTarget.java @@ -10,7 +10,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAINearestAttackableTarget.java b/src/game/java/net/minecraft/entity/ai/EntityAINearestAttackableTarget.java index 1dc84c63..0238cb5b 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAINearestAttackableTarget.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAINearestAttackableTarget.java @@ -17,7 +17,7 @@ import net.minecraft.util.EntitySelectors; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIOcelotAttack.java b/src/game/java/net/minecraft/entity/ai/EntityAIOcelotAttack.java index 59e1707f..6e9d8154 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIOcelotAttack.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIOcelotAttack.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIOcelotSit.java b/src/game/java/net/minecraft/entity/ai/EntityAIOcelotSit.java index 0fb7cd76..1be6bef6 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIOcelotSit.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIOcelotSit.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIOpenDoor.java b/src/game/java/net/minecraft/entity/ai/EntityAIOpenDoor.java index af197f04..9c172ce5 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIOpenDoor.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIOpenDoor.java @@ -8,7 +8,7 @@ import net.minecraft.entity.EntityLiving; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIOwnerHurtByTarget.java b/src/game/java/net/minecraft/entity/ai/EntityAIOwnerHurtByTarget.java index 5bd52e9d..a8edf950 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIOwnerHurtByTarget.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIOwnerHurtByTarget.java @@ -9,7 +9,7 @@ import net.minecraft.entity.passive.EntityTameable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIOwnerHurtTarget.java b/src/game/java/net/minecraft/entity/ai/EntityAIOwnerHurtTarget.java index d4887688..0d85205c 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIOwnerHurtTarget.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIOwnerHurtTarget.java @@ -9,7 +9,7 @@ import net.minecraft.entity.passive.EntityTameable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIPanic.java b/src/game/java/net/minecraft/entity/ai/EntityAIPanic.java index 5c48292c..9e832e96 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIPanic.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIPanic.java @@ -9,7 +9,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIPlay.java b/src/game/java/net/minecraft/entity/ai/EntityAIPlay.java index e85cbbea..5f69f619 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIPlay.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIPlay.java @@ -11,7 +11,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIRestrictOpenDoor.java b/src/game/java/net/minecraft/entity/ai/EntityAIRestrictOpenDoor.java index abf27574..d08b1e41 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIRestrictOpenDoor.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIRestrictOpenDoor.java @@ -12,7 +12,7 @@ import net.minecraft.village.VillageDoorInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIRestrictSun.java b/src/game/java/net/minecraft/entity/ai/EntityAIRestrictSun.java index a1ea8d29..71ed47f5 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIRestrictSun.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIRestrictSun.java @@ -9,7 +9,7 @@ import net.minecraft.pathfinding.PathNavigateGround; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIRunAroundLikeCrazy.java b/src/game/java/net/minecraft/entity/ai/EntityAIRunAroundLikeCrazy.java index 51d594dc..d1f59917 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIRunAroundLikeCrazy.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIRunAroundLikeCrazy.java @@ -11,7 +11,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAISit.java b/src/game/java/net/minecraft/entity/ai/EntityAISit.java index 0a8cdfc9..5c8ca4af 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAISit.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAISit.java @@ -9,7 +9,7 @@ import net.minecraft.entity.passive.EntityTameable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAISwimming.java b/src/game/java/net/minecraft/entity/ai/EntityAISwimming.java index 59640d89..79a39b28 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAISwimming.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAISwimming.java @@ -9,7 +9,7 @@ import net.minecraft.pathfinding.PathNavigateGround; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAITarget.java b/src/game/java/net/minecraft/entity/ai/EntityAITarget.java index 99a647d1..110af459 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAITarget.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAITarget.java @@ -21,7 +21,7 @@ import org.apache.commons.lang3.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAITargetNonTamed.java b/src/game/java/net/minecraft/entity/ai/EntityAITargetNonTamed.java index 123b8f93..615da1c3 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAITargetNonTamed.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAITargetNonTamed.java @@ -10,7 +10,7 @@ import net.minecraft.entity.passive.EntityTameable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAITasks.java b/src/game/java/net/minecraft/entity/ai/EntityAITasks.java index ceb0f232..389843e2 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAITasks.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAITasks.java @@ -12,7 +12,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAITempt.java b/src/game/java/net/minecraft/entity/ai/EntityAITempt.java index 4401858d..517c049c 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAITempt.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAITempt.java @@ -12,7 +12,7 @@ import net.minecraft.pathfinding.PathNavigateGround; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAITradePlayer.java b/src/game/java/net/minecraft/entity/ai/EntityAITradePlayer.java index bc98b8f2..191641d5 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAITradePlayer.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAITradePlayer.java @@ -10,7 +10,7 @@ import net.minecraft.inventory.Container; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIVillagerInteract.java b/src/game/java/net/minecraft/entity/ai/EntityAIVillagerInteract.java index 350edb36..5c1b14e2 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIVillagerInteract.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIVillagerInteract.java @@ -14,7 +14,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIVillagerMate.java b/src/game/java/net/minecraft/entity/ai/EntityAIVillagerMate.java index ea4622a4..11ea8b6b 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIVillagerMate.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIVillagerMate.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIWander.java b/src/game/java/net/minecraft/entity/ai/EntityAIWander.java index 83b2f3fe..a351b3a6 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIWander.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIWander.java @@ -9,7 +9,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIWatchClosest.java b/src/game/java/net/minecraft/entity/ai/EntityAIWatchClosest.java index 74e79dc5..befbc597 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIWatchClosest.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIWatchClosest.java @@ -10,7 +10,7 @@ import net.minecraft.entity.player.EntityPlayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIWatchClosest2.java b/src/game/java/net/minecraft/entity/ai/EntityAIWatchClosest2.java index 6f716971..ed5f042b 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIWatchClosest2.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIWatchClosest2.java @@ -9,7 +9,7 @@ import net.minecraft.entity.EntityLiving; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityJumpHelper.java b/src/game/java/net/minecraft/entity/ai/EntityJumpHelper.java index 69f8d637..9e364aca 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityJumpHelper.java +++ b/src/game/java/net/minecraft/entity/ai/EntityJumpHelper.java @@ -8,7 +8,7 @@ import net.minecraft.entity.EntityLiving; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityLookHelper.java b/src/game/java/net/minecraft/entity/ai/EntityLookHelper.java index 23cbbee6..ae07e749 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityLookHelper.java +++ b/src/game/java/net/minecraft/entity/ai/EntityLookHelper.java @@ -11,7 +11,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityMinecartMobSpawner.java b/src/game/java/net/minecraft/entity/ai/EntityMinecartMobSpawner.java index 53b72e30..63099b73 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityMinecartMobSpawner.java +++ b/src/game/java/net/minecraft/entity/ai/EntityMinecartMobSpawner.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntityMoveHelper.java b/src/game/java/net/minecraft/entity/ai/EntityMoveHelper.java index 3aaa53db..a05c12b2 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityMoveHelper.java +++ b/src/game/java/net/minecraft/entity/ai/EntityMoveHelper.java @@ -10,7 +10,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/EntitySenses.java b/src/game/java/net/minecraft/entity/ai/EntitySenses.java index df71fe85..e4052b07 100755 --- a/src/game/java/net/minecraft/entity/ai/EntitySenses.java +++ b/src/game/java/net/minecraft/entity/ai/EntitySenses.java @@ -11,7 +11,7 @@ import net.minecraft.entity.EntityLiving; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/RandomPositionGenerator.java b/src/game/java/net/minecraft/entity/ai/RandomPositionGenerator.java index 0caab242..660e918d 100755 --- a/src/game/java/net/minecraft/entity/ai/RandomPositionGenerator.java +++ b/src/game/java/net/minecraft/entity/ai/RandomPositionGenerator.java @@ -12,7 +12,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/attributes/AttributeModifier.java b/src/game/java/net/minecraft/entity/ai/attributes/AttributeModifier.java index 1354318e..0a5ccc13 100755 --- a/src/game/java/net/minecraft/entity/ai/attributes/AttributeModifier.java +++ b/src/game/java/net/minecraft/entity/ai/attributes/AttributeModifier.java @@ -13,7 +13,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/attributes/BaseAttribute.java b/src/game/java/net/minecraft/entity/ai/attributes/BaseAttribute.java index e1c1ca80..a0ca26f7 100755 --- a/src/game/java/net/minecraft/entity/ai/attributes/BaseAttribute.java +++ b/src/game/java/net/minecraft/entity/ai/attributes/BaseAttribute.java @@ -6,7 +6,7 @@ package net.minecraft.entity.ai.attributes; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/attributes/BaseAttributeMap.java b/src/game/java/net/minecraft/entity/ai/attributes/BaseAttributeMap.java index 4bd85ac5..32b3d6c6 100755 --- a/src/game/java/net/minecraft/entity/ai/attributes/BaseAttributeMap.java +++ b/src/game/java/net/minecraft/entity/ai/attributes/BaseAttributeMap.java @@ -16,7 +16,7 @@ import net.minecraft.server.management.LowerStringMap; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/attributes/IAttribute.java b/src/game/java/net/minecraft/entity/ai/attributes/IAttribute.java index dc97bd0c..bfd6e322 100755 --- a/src/game/java/net/minecraft/entity/ai/attributes/IAttribute.java +++ b/src/game/java/net/minecraft/entity/ai/attributes/IAttribute.java @@ -6,7 +6,7 @@ package net.minecraft.entity.ai.attributes; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/attributes/IAttributeInstance.java b/src/game/java/net/minecraft/entity/ai/attributes/IAttributeInstance.java index f6db33c0..24af7de4 100755 --- a/src/game/java/net/minecraft/entity/ai/attributes/IAttributeInstance.java +++ b/src/game/java/net/minecraft/entity/ai/attributes/IAttributeInstance.java @@ -9,7 +9,7 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/attributes/ModifiableAttributeInstance.java b/src/game/java/net/minecraft/entity/ai/attributes/ModifiableAttributeInstance.java index a14e3d0b..bcf11df5 100755 --- a/src/game/java/net/minecraft/entity/ai/attributes/ModifiableAttributeInstance.java +++ b/src/game/java/net/minecraft/entity/ai/attributes/ModifiableAttributeInstance.java @@ -7,6 +7,8 @@ import java.util.Map; import java.util.Set; import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -17,7 +19,7 @@ import com.google.common.collect.Sets; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -34,7 +36,7 @@ import com.google.common.collect.Sets; public class ModifiableAttributeInstance implements IAttributeInstance { private final BaseAttributeMap attributeMap; private final IAttribute genericAttribute; - private final Map> mapByOperation = Maps.newHashMap(); + private final IntObjectMap> mapByOperation = new IntObjectHashMap<>(); private final Map> mapByName = Maps.newHashMap(); private final Map mapByUUID = Maps.newHashMap(); private double baseValue; @@ -47,7 +49,7 @@ public class ModifiableAttributeInstance implements IAttributeInstance { this.baseValue = genericAttributeIn.getDefaultValue(); for (int i = 0; i < 3; ++i) { - this.mapByOperation.put(Integer.valueOf(i), Sets.newHashSet()); + this.mapByOperation.put(i, Sets.newHashSet()); } } @@ -71,7 +73,7 @@ public class ModifiableAttributeInstance implements IAttributeInstance { } public Collection getModifiersByOperation(int i) { - return (Collection) this.mapByOperation.get(Integer.valueOf(i)); + return this.mapByOperation.get(i); } public Collection func_111122_c() { @@ -105,7 +107,7 @@ public class ModifiableAttributeInstance implements IAttributeInstance { this.mapByName.put(attributemodifier.getName(), object); } - ((Set) this.mapByOperation.get(Integer.valueOf(attributemodifier.getOperation()))).add(attributemodifier); + ((Set) this.mapByOperation.get(attributemodifier.getOperation())).add(attributemodifier); ((Set) object).add(attributemodifier); this.mapByUUID.put(attributemodifier.getID(), attributemodifier); this.flagForUpdate(); @@ -119,7 +121,7 @@ public class ModifiableAttributeInstance implements IAttributeInstance { public void removeModifier(AttributeModifier attributemodifier) { for (int i = 0; i < 3; ++i) { - Set set = (Set) this.mapByOperation.get(Integer.valueOf(i)); + Set set = (Set) this.mapByOperation.get(i); set.remove(attributemodifier); } diff --git a/src/game/java/net/minecraft/entity/ai/attributes/RangedAttribute.java b/src/game/java/net/minecraft/entity/ai/attributes/RangedAttribute.java index 7a9d4a88..ad2d8f70 100755 --- a/src/game/java/net/minecraft/entity/ai/attributes/RangedAttribute.java +++ b/src/game/java/net/minecraft/entity/ai/attributes/RangedAttribute.java @@ -8,7 +8,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/ai/attributes/ServersideAttributeMap.java b/src/game/java/net/minecraft/entity/ai/attributes/ServersideAttributeMap.java index 1d4e627f..2fd95192 100755 --- a/src/game/java/net/minecraft/entity/ai/attributes/ServersideAttributeMap.java +++ b/src/game/java/net/minecraft/entity/ai/attributes/ServersideAttributeMap.java @@ -13,7 +13,7 @@ import net.minecraft.server.management.LowerStringMap; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/boss/BossStatus.java b/src/game/java/net/minecraft/entity/boss/BossStatus.java index 4883624d..1e1be893 100755 --- a/src/game/java/net/minecraft/entity/boss/BossStatus.java +++ b/src/game/java/net/minecraft/entity/boss/BossStatus.java @@ -6,7 +6,7 @@ package net.minecraft.entity.boss; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/boss/EntityDragon.java b/src/game/java/net/minecraft/entity/boss/EntityDragon.java index d2bbe1cf..d5dcd8ef 100755 --- a/src/game/java/net/minecraft/entity/boss/EntityDragon.java +++ b/src/game/java/net/minecraft/entity/boss/EntityDragon.java @@ -34,7 +34,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/boss/EntityDragonPart.java b/src/game/java/net/minecraft/entity/boss/EntityDragonPart.java index 0d9569df..a489e975 100755 --- a/src/game/java/net/minecraft/entity/boss/EntityDragonPart.java +++ b/src/game/java/net/minecraft/entity/boss/EntityDragonPart.java @@ -11,7 +11,7 @@ import net.minecraft.util.DamageSource; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/boss/EntityWither.java b/src/game/java/net/minecraft/entity/boss/EntityWither.java index b24e3149..ab882fd4 100755 --- a/src/game/java/net/minecraft/entity/boss/EntityWither.java +++ b/src/game/java/net/minecraft/entity/boss/EntityWither.java @@ -43,7 +43,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/boss/IBossDisplayData.java b/src/game/java/net/minecraft/entity/boss/IBossDisplayData.java index 0fce6f54..f1b4f6b0 100755 --- a/src/game/java/net/minecraft/entity/boss/IBossDisplayData.java +++ b/src/game/java/net/minecraft/entity/boss/IBossDisplayData.java @@ -8,7 +8,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/effect/EntityLightningBolt.java b/src/game/java/net/minecraft/entity/effect/EntityLightningBolt.java index 26869962..6cc0887c 100755 --- a/src/game/java/net/minecraft/entity/effect/EntityLightningBolt.java +++ b/src/game/java/net/minecraft/entity/effect/EntityLightningBolt.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/effect/EntityWeatherEffect.java b/src/game/java/net/minecraft/entity/effect/EntityWeatherEffect.java index 2b9fe4e3..e5e50aa5 100755 --- a/src/game/java/net/minecraft/entity/effect/EntityWeatherEffect.java +++ b/src/game/java/net/minecraft/entity/effect/EntityWeatherEffect.java @@ -9,7 +9,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityArmorStand.java b/src/game/java/net/minecraft/entity/item/EntityArmorStand.java index d122a794..eb9334cc 100755 --- a/src/game/java/net/minecraft/entity/item/EntityArmorStand.java +++ b/src/game/java/net/minecraft/entity/item/EntityArmorStand.java @@ -29,7 +29,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityBoat.java b/src/game/java/net/minecraft/entity/item/EntityBoat.java index 8b0aedcc..4fa4b450 100755 --- a/src/game/java/net/minecraft/entity/item/EntityBoat.java +++ b/src/game/java/net/minecraft/entity/item/EntityBoat.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityEnderCrystal.java b/src/game/java/net/minecraft/entity/item/EntityEnderCrystal.java index 1029905c..7911887b 100755 --- a/src/game/java/net/minecraft/entity/item/EntityEnderCrystal.java +++ b/src/game/java/net/minecraft/entity/item/EntityEnderCrystal.java @@ -15,7 +15,7 @@ import net.minecraft.world.WorldProviderEnd; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityEnderEye.java b/src/game/java/net/minecraft/entity/item/EntityEnderEye.java index 9f689eff..6f731780 100755 --- a/src/game/java/net/minecraft/entity/item/EntityEnderEye.java +++ b/src/game/java/net/minecraft/entity/item/EntityEnderEye.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityEnderPearl.java b/src/game/java/net/minecraft/entity/item/EntityEnderPearl.java index 8f572957..f3f8186b 100755 --- a/src/game/java/net/minecraft/entity/item/EntityEnderPearl.java +++ b/src/game/java/net/minecraft/entity/item/EntityEnderPearl.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityExpBottle.java b/src/game/java/net/minecraft/entity/item/EntityExpBottle.java index 27216a15..cdb4c9c9 100755 --- a/src/game/java/net/minecraft/entity/item/EntityExpBottle.java +++ b/src/game/java/net/minecraft/entity/item/EntityExpBottle.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityFallingBlock.java b/src/game/java/net/minecraft/entity/item/EntityFallingBlock.java index 6aab3283..0b9c754b 100755 --- a/src/game/java/net/minecraft/entity/item/EntityFallingBlock.java +++ b/src/game/java/net/minecraft/entity/item/EntityFallingBlock.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityFireworkRocket.java b/src/game/java/net/minecraft/entity/item/EntityFireworkRocket.java index e8c9a7d3..ea5796f5 100755 --- a/src/game/java/net/minecraft/entity/item/EntityFireworkRocket.java +++ b/src/game/java/net/minecraft/entity/item/EntityFireworkRocket.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityItem.java b/src/game/java/net/minecraft/entity/item/EntityItem.java index df3b79ce..5d1c290e 100755 --- a/src/game/java/net/minecraft/entity/item/EntityItem.java +++ b/src/game/java/net/minecraft/entity/item/EntityItem.java @@ -26,7 +26,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityItemFrame.java b/src/game/java/net/minecraft/entity/item/EntityItemFrame.java index 421e55f4..bce5fa76 100755 --- a/src/game/java/net/minecraft/entity/item/EntityItemFrame.java +++ b/src/game/java/net/minecraft/entity/item/EntityItemFrame.java @@ -22,7 +22,7 @@ import net.minecraft.world.storage.MapData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityMinecart.java b/src/game/java/net/minecraft/entity/item/EntityMinecart.java index 168e5bb6..ccc31536 100755 --- a/src/game/java/net/minecraft/entity/item/EntityMinecart.java +++ b/src/game/java/net/minecraft/entity/item/EntityMinecart.java @@ -1,10 +1,8 @@ package net.minecraft.entity.item; import java.util.List; -import java.util.Map; - -import com.google.common.collect.Maps; - +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import net.minecraft.block.Block; import net.minecraft.block.BlockRailBase; import net.minecraft.block.BlockRailPowered; @@ -39,7 +37,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -990,7 +988,7 @@ public abstract class EntityMinecart extends Entity implements IWorldNameable { TNT(3, "MinecartTNT"), SPAWNER(4, "MinecartSpawner"), HOPPER(5, "MinecartHopper"), COMMAND_BLOCK(6, "MinecartCommandBlock"); - private static final Map ID_LOOKUP = Maps.newHashMap(); + private static final IntObjectMap ID_LOOKUP = new IntObjectHashMap<>(); private final int networkID; private final String name; @@ -1012,15 +1010,14 @@ public abstract class EntityMinecart extends Entity implements IWorldNameable { } public static EntityMinecart.EnumMinecartType byNetworkID(int id) { - EntityMinecart.EnumMinecartType entityminecart$enumminecarttype = (EntityMinecart.EnumMinecartType) ID_LOOKUP - .get(Integer.valueOf(id)); + EntityMinecart.EnumMinecartType entityminecart$enumminecarttype = ID_LOOKUP.get(id); return entityminecart$enumminecarttype == null ? RIDEABLE : entityminecart$enumminecarttype; } static { EntityMinecart.EnumMinecartType[] types = values(); for (int i = 0; i < types.length; ++i) { - ID_LOOKUP.put(Integer.valueOf(types[i].getNetworkID()), types[i]); + ID_LOOKUP.put(types[i].getNetworkID(), types[i]); } } diff --git a/src/game/java/net/minecraft/entity/item/EntityMinecartChest.java b/src/game/java/net/minecraft/entity/item/EntityMinecartChest.java index 9d79b40b..32448212 100755 --- a/src/game/java/net/minecraft/entity/item/EntityMinecartChest.java +++ b/src/game/java/net/minecraft/entity/item/EntityMinecartChest.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityMinecartContainer.java b/src/game/java/net/minecraft/entity/item/EntityMinecartContainer.java index 7cb5e49e..b30736bb 100755 --- a/src/game/java/net/minecraft/entity/item/EntityMinecartContainer.java +++ b/src/game/java/net/minecraft/entity/item/EntityMinecartContainer.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityMinecartEmpty.java b/src/game/java/net/minecraft/entity/item/EntityMinecartEmpty.java index f4491813..28810172 100755 --- a/src/game/java/net/minecraft/entity/item/EntityMinecartEmpty.java +++ b/src/game/java/net/minecraft/entity/item/EntityMinecartEmpty.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityMinecartFurnace.java b/src/game/java/net/minecraft/entity/item/EntityMinecartFurnace.java index 3a7f833d..726e320d 100755 --- a/src/game/java/net/minecraft/entity/item/EntityMinecartFurnace.java +++ b/src/game/java/net/minecraft/entity/item/EntityMinecartFurnace.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityMinecartHopper.java b/src/game/java/net/minecraft/entity/item/EntityMinecartHopper.java index db14dd10..a3edb719 100755 --- a/src/game/java/net/minecraft/entity/item/EntityMinecartHopper.java +++ b/src/game/java/net/minecraft/entity/item/EntityMinecartHopper.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityMinecartTNT.java b/src/game/java/net/minecraft/entity/item/EntityMinecartTNT.java index a508cdad..41963ceb 100755 --- a/src/game/java/net/minecraft/entity/item/EntityMinecartTNT.java +++ b/src/game/java/net/minecraft/entity/item/EntityMinecartTNT.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityPainting.java b/src/game/java/net/minecraft/entity/item/EntityPainting.java index 8dd0942a..3e724c5a 100755 --- a/src/game/java/net/minecraft/entity/item/EntityPainting.java +++ b/src/game/java/net/minecraft/entity/item/EntityPainting.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityTNTPrimed.java b/src/game/java/net/minecraft/entity/item/EntityTNTPrimed.java index 22a78418..924dace2 100755 --- a/src/game/java/net/minecraft/entity/item/EntityTNTPrimed.java +++ b/src/game/java/net/minecraft/entity/item/EntityTNTPrimed.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/item/EntityXPOrb.java b/src/game/java/net/minecraft/entity/item/EntityXPOrb.java index 1fac03a5..8673ffc9 100755 --- a/src/game/java/net/minecraft/entity/item/EntityXPOrb.java +++ b/src/game/java/net/minecraft/entity/item/EntityXPOrb.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntityBlaze.java b/src/game/java/net/minecraft/entity/monster/EntityBlaze.java index 009c40c0..5c28f784 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityBlaze.java +++ b/src/game/java/net/minecraft/entity/monster/EntityBlaze.java @@ -26,7 +26,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntityCaveSpider.java b/src/game/java/net/minecraft/entity/monster/EntityCaveSpider.java index 58ec93dd..99c8e176 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityCaveSpider.java +++ b/src/game/java/net/minecraft/entity/monster/EntityCaveSpider.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntityCreeper.java b/src/game/java/net/minecraft/entity/monster/EntityCreeper.java index c949c5ac..24b7a55a 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityCreeper.java +++ b/src/game/java/net/minecraft/entity/monster/EntityCreeper.java @@ -29,7 +29,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntityEnderman.java b/src/game/java/net/minecraft/entity/monster/EntityEnderman.java index 01a37163..d16be41d 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityEnderman.java +++ b/src/game/java/net/minecraft/entity/monster/EntityEnderman.java @@ -45,7 +45,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -511,7 +511,10 @@ public class EntityEnderman extends EntityMob { int j = MathHelper.floor_double(this.enderman.posY + random.nextDouble() * 2.0D); int k = MathHelper.floor_double(this.enderman.posZ - 1.0D + random.nextDouble() * 2.0D); BlockPos blockpos = new BlockPos(i, j, k); - Block block = world.getBlockState(blockpos).getBlock(); + IBlockState iblockstate = world.getBlockState(blockpos); + if (iblockstate == null) + return; + Block block = iblockstate.getBlock(); Block block1 = world.getBlockState(blockpos.down()).getBlock(); if (this.func_179474_a(world, blockpos, this.enderman.getHeldBlockState().getBlock(), block, block1)) { world.setBlockState(blockpos, this.enderman.getHeldBlockState(), 3); @@ -548,7 +551,9 @@ public class EntityEnderman extends EntityMob { int j = MathHelper.floor_double(this.enderman.posY + random.nextDouble() * 3.0D); int k = MathHelper.floor_double(this.enderman.posZ - 2.0D + random.nextDouble() * 4.0D); BlockPos blockpos = new BlockPos(i, j, k); - IBlockState iblockstate = world.getBlockState(blockpos); + IBlockState iblockstate = world.getBlockStateIfLoaded(blockpos); + if (iblockstate == null) + return; Block block = iblockstate.getBlock(); if (EntityEnderman.carriableBlocks.contains(block)) { this.enderman.setHeldBlockState(iblockstate); diff --git a/src/game/java/net/minecraft/entity/monster/EntityEndermite.java b/src/game/java/net/minecraft/entity/monster/EntityEndermite.java index 7c5f74dc..bb962b79 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityEndermite.java +++ b/src/game/java/net/minecraft/entity/monster/EntityEndermite.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntityGhast.java b/src/game/java/net/minecraft/entity/monster/EntityGhast.java index b1e6cb34..3f4dffaa 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityGhast.java +++ b/src/game/java/net/minecraft/entity/monster/EntityGhast.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntityGiantZombie.java b/src/game/java/net/minecraft/entity/monster/EntityGiantZombie.java index 5f6f5538..32c49559 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityGiantZombie.java +++ b/src/game/java/net/minecraft/entity/monster/EntityGiantZombie.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntityGolem.java b/src/game/java/net/minecraft/entity/monster/EntityGolem.java index cce18c88..cc0f51f1 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityGolem.java +++ b/src/game/java/net/minecraft/entity/monster/EntityGolem.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntityGuardian.java b/src/game/java/net/minecraft/entity/monster/EntityGuardian.java index 1f5ec875..bf36c0af 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityGuardian.java +++ b/src/game/java/net/minecraft/entity/monster/EntityGuardian.java @@ -45,7 +45,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntityIronGolem.java b/src/game/java/net/minecraft/entity/monster/EntityIronGolem.java index 0248e3cf..be606c40 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityIronGolem.java +++ b/src/game/java/net/minecraft/entity/monster/EntityIronGolem.java @@ -40,7 +40,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntityMagmaCube.java b/src/game/java/net/minecraft/entity/monster/EntityMagmaCube.java index ace061a2..717c494c 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityMagmaCube.java +++ b/src/game/java/net/minecraft/entity/monster/EntityMagmaCube.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntityMob.java b/src/game/java/net/minecraft/entity/monster/EntityMob.java index 337fd02e..49b14cf1 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityMob.java +++ b/src/game/java/net/minecraft/entity/monster/EntityMob.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntityPigZombie.java b/src/game/java/net/minecraft/entity/monster/EntityPigZombie.java index 60d4d112..484e7a3e 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityPigZombie.java +++ b/src/game/java/net/minecraft/entity/monster/EntityPigZombie.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntitySilverfish.java b/src/game/java/net/minecraft/entity/monster/EntitySilverfish.java index a6d22b3f..aedb4607 100755 --- a/src/game/java/net/minecraft/entity/monster/EntitySilverfish.java +++ b/src/game/java/net/minecraft/entity/monster/EntitySilverfish.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntitySkeleton.java b/src/game/java/net/minecraft/entity/monster/EntitySkeleton.java index 7821bc79..96cb576e 100755 --- a/src/game/java/net/minecraft/entity/monster/EntitySkeleton.java +++ b/src/game/java/net/minecraft/entity/monster/EntitySkeleton.java @@ -45,7 +45,7 @@ import net.minecraft.world.WorldProviderHell; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntitySlime.java b/src/game/java/net/minecraft/entity/monster/EntitySlime.java index 0c948298..d72447da 100755 --- a/src/game/java/net/minecraft/entity/monster/EntitySlime.java +++ b/src/game/java/net/minecraft/entity/monster/EntitySlime.java @@ -31,7 +31,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntitySnowman.java b/src/game/java/net/minecraft/entity/monster/EntitySnowman.java index 28c22eb2..0fa9a4f3 100755 --- a/src/game/java/net/minecraft/entity/monster/EntitySnowman.java +++ b/src/game/java/net/minecraft/entity/monster/EntitySnowman.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntitySpider.java b/src/game/java/net/minecraft/entity/monster/EntitySpider.java index f84df437..d3516fe1 100755 --- a/src/game/java/net/minecraft/entity/monster/EntitySpider.java +++ b/src/game/java/net/minecraft/entity/monster/EntitySpider.java @@ -33,7 +33,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntityWitch.java b/src/game/java/net/minecraft/entity/monster/EntityWitch.java index f708fc28..9d7922b3 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityWitch.java +++ b/src/game/java/net/minecraft/entity/monster/EntityWitch.java @@ -33,7 +33,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/EntityZombie.java b/src/game/java/net/minecraft/entity/monster/EntityZombie.java index b4bf2cff..7864563d 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityZombie.java +++ b/src/game/java/net/minecraft/entity/monster/EntityZombie.java @@ -49,7 +49,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/monster/IMob.java b/src/game/java/net/minecraft/entity/monster/IMob.java index 638a5fed..a40cc7a2 100755 --- a/src/game/java/net/minecraft/entity/monster/IMob.java +++ b/src/game/java/net/minecraft/entity/monster/IMob.java @@ -11,7 +11,7 @@ import net.minecraft.entity.passive.IAnimals; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/passive/EntityAmbientCreature.java b/src/game/java/net/minecraft/entity/passive/EntityAmbientCreature.java index e5da0fda..b8d630cd 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityAmbientCreature.java +++ b/src/game/java/net/minecraft/entity/passive/EntityAmbientCreature.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/passive/EntityAnimal.java b/src/game/java/net/minecraft/entity/passive/EntityAnimal.java index 848e7c78..3d07d4f6 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityAnimal.java +++ b/src/game/java/net/minecraft/entity/passive/EntityAnimal.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/passive/EntityBat.java b/src/game/java/net/minecraft/entity/passive/EntityBat.java index a1571b0d..7e64ca9f 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityBat.java +++ b/src/game/java/net/minecraft/entity/passive/EntityBat.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/passive/EntityChicken.java b/src/game/java/net/minecraft/entity/passive/EntityChicken.java index 5ab6f74f..3f39df51 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityChicken.java +++ b/src/game/java/net/minecraft/entity/passive/EntityChicken.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/passive/EntityCow.java b/src/game/java/net/minecraft/entity/passive/EntityCow.java index cdfac514..97dc0d47 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityCow.java +++ b/src/game/java/net/minecraft/entity/passive/EntityCow.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/passive/EntityHorse.java b/src/game/java/net/minecraft/entity/passive/EntityHorse.java index 44fde571..ec752796 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityHorse.java +++ b/src/game/java/net/minecraft/entity/passive/EntityHorse.java @@ -49,7 +49,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/passive/EntityMooshroom.java b/src/game/java/net/minecraft/entity/passive/EntityMooshroom.java index 6e126596..e84ffc7f 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityMooshroom.java +++ b/src/game/java/net/minecraft/entity/passive/EntityMooshroom.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/passive/EntityOcelot.java b/src/game/java/net/minecraft/entity/passive/EntityOcelot.java index 6cc07c7c..6d91c2a3 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityOcelot.java +++ b/src/game/java/net/minecraft/entity/passive/EntityOcelot.java @@ -37,7 +37,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/passive/EntityPig.java b/src/game/java/net/minecraft/entity/passive/EntityPig.java index c39faf05..c66314ae 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityPig.java +++ b/src/game/java/net/minecraft/entity/passive/EntityPig.java @@ -30,7 +30,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/passive/EntityRabbit.java b/src/game/java/net/minecraft/entity/passive/EntityRabbit.java index ca1bd665..b80583e9 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityRabbit.java +++ b/src/game/java/net/minecraft/entity/passive/EntityRabbit.java @@ -44,7 +44,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/passive/EntitySheep.java b/src/game/java/net/minecraft/entity/passive/EntitySheep.java index e23cd759..a94e8b1b 100755 --- a/src/game/java/net/minecraft/entity/passive/EntitySheep.java +++ b/src/game/java/net/minecraft/entity/passive/EntitySheep.java @@ -39,7 +39,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/passive/EntitySquid.java b/src/game/java/net/minecraft/entity/passive/EntitySquid.java index 9a2fd179..1d774f34 100755 --- a/src/game/java/net/minecraft/entity/passive/EntitySquid.java +++ b/src/game/java/net/minecraft/entity/passive/EntitySquid.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/passive/EntityTameable.java b/src/game/java/net/minecraft/entity/passive/EntityTameable.java index f9998a09..14a96812 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityTameable.java +++ b/src/game/java/net/minecraft/entity/passive/EntityTameable.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/passive/EntityVillager.java b/src/game/java/net/minecraft/entity/passive/EntityVillager.java index e4978e3f..411f8667 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityVillager.java +++ b/src/game/java/net/minecraft/entity/passive/EntityVillager.java @@ -57,7 +57,6 @@ import net.minecraft.util.DamageSource; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.IChatComponent; import net.minecraft.util.MathHelper; -import net.minecraft.util.Tuple; import net.minecraft.village.MerchantRecipe; import net.minecraft.village.MerchantRecipeList; import net.minecraft.village.Village; @@ -70,7 +69,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -1109,16 +1108,25 @@ public class EntityVillager extends EntityAgeable implements IMerchant, INpc { } } - static class PriceInfo extends Tuple { + static class PriceInfo { + private int a; + private int b; + public PriceInfo(int parInt1, int parInt2) { - super(Integer.valueOf(parInt1), Integer.valueOf(parInt2)); + this.a = parInt1; + this.b = parInt2; + } + + public int getFirst() { + return this.a; + } + + public int getSecond() { + return this.b; } public int getPrice(EaglercraftRandom rand) { - return ((Integer) this.getFirst()).intValue() >= ((Integer) this.getSecond()).intValue() - ? ((Integer) this.getFirst()).intValue() - : ((Integer) this.getFirst()).intValue() + rand.nextInt( - ((Integer) this.getSecond()).intValue() - ((Integer) this.getFirst()).intValue() + 1); + return (a >= b) ? a : a + rand.nextInt(b - a + 1); } } } \ No newline at end of file diff --git a/src/game/java/net/minecraft/entity/passive/EntityWaterMob.java b/src/game/java/net/minecraft/entity/passive/EntityWaterMob.java index f79eb45e..fb235304 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityWaterMob.java +++ b/src/game/java/net/minecraft/entity/passive/EntityWaterMob.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/passive/EntityWolf.java b/src/game/java/net/minecraft/entity/passive/EntityWolf.java index 0beb8979..379595c8 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityWolf.java +++ b/src/game/java/net/minecraft/entity/passive/EntityWolf.java @@ -44,7 +44,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/passive/IAnimals.java b/src/game/java/net/minecraft/entity/passive/IAnimals.java index b14daacd..e16bf5af 100755 --- a/src/game/java/net/minecraft/entity/passive/IAnimals.java +++ b/src/game/java/net/minecraft/entity/passive/IAnimals.java @@ -6,7 +6,7 @@ package net.minecraft.entity.passive; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/player/EntityPlayer.java b/src/game/java/net/minecraft/entity/player/EntityPlayer.java index a1941f56..4db1a4cb 100755 --- a/src/game/java/net/minecraft/entity/player/EntityPlayer.java +++ b/src/game/java/net/minecraft/entity/player/EntityPlayer.java @@ -83,7 +83,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/player/EntityPlayerMP.java b/src/game/java/net/minecraft/entity/player/EntityPlayerMP.java index 2bb2b37d..dca4d0ac 100755 --- a/src/game/java/net/minecraft/entity/player/EntityPlayerMP.java +++ b/src/game/java/net/minecraft/entity/player/EntityPlayerMP.java @@ -1,5 +1,11 @@ package net.minecraft.entity.player; +import com.carrotsearch.hppc.IntArrayDeque; +import com.carrotsearch.hppc.IntDeque; +import com.carrotsearch.hppc.LongHashSet; +import com.carrotsearch.hppc.LongSet; +import com.carrotsearch.hppc.cursors.IntCursor; +import com.carrotsearch.hppc.cursors.LongCursor; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import net.lax1dude.eaglercraft.v1_8.mojang.authlib.GameProfile; @@ -87,7 +93,6 @@ import net.minecraft.util.JsonSerializableSet; import net.minecraft.util.MathHelper; import net.minecraft.util.ReportedException; import net.minecraft.village.MerchantRecipeList; -import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.IInteractionObject; import net.minecraft.world.ILockableContainer; import net.minecraft.world.WorldServer; @@ -105,7 +110,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -131,11 +136,11 @@ public class EntityPlayerMP extends EntityPlayer implements ICrafting { /**+ * LinkedList that holds the loaded chunks. */ - public final List loadedChunks = Lists.newLinkedList(); + public final LongSet loadedChunks = new LongHashSet(); /**+ * entities added to this list will be packet29'd to the player */ - private final List destroyedItemsNetCache = Lists.newLinkedList(); + private final IntDeque destroyedItemsNetCache = new IntArrayDeque(); private final StatisticsFile statsFile; /**+ * the total health of the player, includes actual health and @@ -287,56 +292,49 @@ public class EntityPlayerMP extends EntityPlayer implements ICrafting { while (!this.destroyedItemsNetCache.isEmpty()) { int i = Math.min(this.destroyedItemsNetCache.size(), Integer.MAX_VALUE); int[] aint = new int[i]; - Iterator iterator = this.destroyedItemsNetCache.iterator(); int j = 0; - while (iterator.hasNext() && j < i) { - aint[j++] = ((Integer) iterator.next()).intValue(); - iterator.remove(); + while (!destroyedItemsNetCache.isEmpty() && j < i) { + aint[j++] = destroyedItemsNetCache.removeFirst(); } this.playerNetServerHandler.sendPacket(new S13PacketDestroyEntities(aint)); } if (!this.loadedChunks.isEmpty()) { - ArrayList arraylist = Lists.newArrayList(); - Iterator iterator1 = this.loadedChunks.iterator(); - ArrayList arraylist1 = Lists.newArrayList(); + ArrayList arraylist = Lists.newArrayList(); + Iterator iterator1 = this.loadedChunks.iterator(); + ArrayList arraylist1 = Lists.newArrayList(); while (iterator1.hasNext() && arraylist.size() < 10) { - ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair) iterator1.next(); - if (chunkcoordintpair != null) { - if (this.worldObj.isBlockLoaded( - new BlockPos(chunkcoordintpair.chunkXPos << 4, 0, chunkcoordintpair.chunkZPos << 4))) { - Chunk chunk = this.worldObj.getChunkFromChunkCoords(chunkcoordintpair.chunkXPos, - chunkcoordintpair.chunkZPos); - if (chunk.isPopulated()) { - arraylist.add(chunk); - arraylist1.addAll(((WorldServer) this.worldObj).getTileEntitiesIn( - chunkcoordintpair.chunkXPos * 16, 0, chunkcoordintpair.chunkZPos * 16, - chunkcoordintpair.chunkXPos * 16 + 16, 256, chunkcoordintpair.chunkZPos * 16 + 16)); - iterator1.remove(); - } + long l = iterator1.next().value; + int chunkXPos = (int) (l & 4294967295L); + int chunkZPos = (int) (l >>> 32); + if (this.worldObj.isBlockLoaded(new BlockPos(chunkXPos << 4, 0, chunkZPos << 4))) { + Chunk chunk = this.worldObj.getChunkFromChunkCoords(chunkXPos, chunkZPos); + if (chunk.isPopulated()) { + arraylist.add(chunk); + arraylist1.addAll(((WorldServer) this.worldObj).getTileEntitiesIn(chunkXPos * 16, 0, + chunkZPos * 16, chunkXPos * 16 + 16, 256, chunkZPos * 16 + 16)); } - } else { - iterator1.remove(); } } if (!arraylist.isEmpty()) { if (arraylist.size() == 1) { - this.playerNetServerHandler - .sendPacket(new S21PacketChunkData((Chunk) arraylist.get(0), true, '\uffff')); + this.playerNetServerHandler.sendPacket(new S21PacketChunkData(arraylist.get(0), true, '\uffff')); } else { this.playerNetServerHandler.sendPacket(new S26PacketMapChunkBulk(arraylist)); } for (int i = 0, l = arraylist1.size(); i < l; ++i) { - this.sendTileEntityUpdate((TileEntity) arraylist1.get(i)); + this.sendTileEntityUpdate(arraylist1.get(i)); } for (int i = 0, l = arraylist.size(); i < l; ++i) { - this.getServerForPlayer().getEntityTracker().func_85172_a(this, (Chunk) arraylist.get(i)); + Chunk c = arraylist.get(i); + this.getServerForPlayer().getEntityTracker().func_85172_a(this, c); + this.loadedChunks.removeAll(c.getChunkCoordLong()); } } } @@ -940,7 +938,9 @@ public class EntityPlayerMP extends EntityPlayer implements ICrafting { this.lastExperience = -1; this.lastHealth = -1.0F; this.lastFoodLevel = -1; - this.destroyedItemsNetCache.addAll(((EntityPlayerMP) oldPlayer).destroyedItemsNetCache); + for (IntCursor cur : ((EntityPlayerMP) oldPlayer).destroyedItemsNetCache) { + destroyedItemsNetCache.addLast(cur.value); + } } protected void onNewPotionEffect(PotionEffect id) { @@ -1086,7 +1086,7 @@ public class EntityPlayerMP extends EntityPlayer implements ICrafting { if (parEntity instanceof EntityPlayer) { this.playerNetServerHandler.sendPacket(new S13PacketDestroyEntities(new int[] { parEntity.getEntityId() })); } else { - this.destroyedItemsNetCache.add(Integer.valueOf(parEntity.getEntityId())); + this.destroyedItemsNetCache.addLast(parEntity.getEntityId()); } } diff --git a/src/game/java/net/minecraft/entity/player/EnumPlayerModelParts.java b/src/game/java/net/minecraft/entity/player/EnumPlayerModelParts.java index dafb46b2..8eebc196 100755 --- a/src/game/java/net/minecraft/entity/player/EnumPlayerModelParts.java +++ b/src/game/java/net/minecraft/entity/player/EnumPlayerModelParts.java @@ -9,7 +9,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/player/InventoryPlayer.java b/src/game/java/net/minecraft/entity/player/InventoryPlayer.java index 3603b56e..30e6571f 100755 --- a/src/game/java/net/minecraft/entity/player/InventoryPlayer.java +++ b/src/game/java/net/minecraft/entity/player/InventoryPlayer.java @@ -23,7 +23,7 @@ import net.minecraft.util.ReportedException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/player/PlayerCapabilities.java b/src/game/java/net/minecraft/entity/player/PlayerCapabilities.java index 7a22ea6a..93af2a77 100755 --- a/src/game/java/net/minecraft/entity/player/PlayerCapabilities.java +++ b/src/game/java/net/minecraft/entity/player/PlayerCapabilities.java @@ -8,7 +8,7 @@ import net.minecraft.nbt.NBTTagCompound; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/projectile/EntityArrow.java b/src/game/java/net/minecraft/entity/projectile/EntityArrow.java index a43a38c2..24024b22 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntityArrow.java +++ b/src/game/java/net/minecraft/entity/projectile/EntityArrow.java @@ -31,7 +31,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/projectile/EntityEgg.java b/src/game/java/net/minecraft/entity/projectile/EntityEgg.java index aa9af05e..c056494e 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntityEgg.java +++ b/src/game/java/net/minecraft/entity/projectile/EntityEgg.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/projectile/EntityFireball.java b/src/game/java/net/minecraft/entity/projectile/EntityFireball.java index 1a5bc51c..b74f19d3 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntityFireball.java +++ b/src/game/java/net/minecraft/entity/projectile/EntityFireball.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/projectile/EntityFishHook.java b/src/game/java/net/minecraft/entity/projectile/EntityFishHook.java index 19557e4b..0c3e2f11 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntityFishHook.java +++ b/src/game/java/net/minecraft/entity/projectile/EntityFishHook.java @@ -35,7 +35,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/projectile/EntityLargeFireball.java b/src/game/java/net/minecraft/entity/projectile/EntityLargeFireball.java index abe2d8c3..04736a3f 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntityLargeFireball.java +++ b/src/game/java/net/minecraft/entity/projectile/EntityLargeFireball.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/projectile/EntityPotion.java b/src/game/java/net/minecraft/entity/projectile/EntityPotion.java index 80c601c1..d687283c 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntityPotion.java +++ b/src/game/java/net/minecraft/entity/projectile/EntityPotion.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/projectile/EntitySmallFireball.java b/src/game/java/net/minecraft/entity/projectile/EntitySmallFireball.java index 0daf2fc7..86049cb1 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntitySmallFireball.java +++ b/src/game/java/net/minecraft/entity/projectile/EntitySmallFireball.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/projectile/EntitySnowball.java b/src/game/java/net/minecraft/entity/projectile/EntitySnowball.java index a2dc92ff..63bd2727 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntitySnowball.java +++ b/src/game/java/net/minecraft/entity/projectile/EntitySnowball.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/projectile/EntityThrowable.java b/src/game/java/net/minecraft/entity/projectile/EntityThrowable.java index 12e09a3e..d9173b27 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntityThrowable.java +++ b/src/game/java/net/minecraft/entity/projectile/EntityThrowable.java @@ -25,7 +25,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/entity/projectile/EntityWitherSkull.java b/src/game/java/net/minecraft/entity/projectile/EntityWitherSkull.java index 28adba76..d80d425b 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntityWitherSkull.java +++ b/src/game/java/net/minecraft/entity/projectile/EntityWitherSkull.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/event/ClickEvent.java b/src/game/java/net/minecraft/event/ClickEvent.java index 652af505..5a33f67c 100755 --- a/src/game/java/net/minecraft/event/ClickEvent.java +++ b/src/game/java/net/minecraft/event/ClickEvent.java @@ -10,7 +10,7 @@ import com.google.common.collect.Maps; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/event/HoverEvent.java b/src/game/java/net/minecraft/event/HoverEvent.java index 70b2fc14..a40d5c33 100755 --- a/src/game/java/net/minecraft/event/HoverEvent.java +++ b/src/game/java/net/minecraft/event/HoverEvent.java @@ -12,7 +12,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/init/Blocks.java b/src/game/java/net/minecraft/init/Blocks.java index 2c7aa7f7..8610d994 100755 --- a/src/game/java/net/minecraft/init/Blocks.java +++ b/src/game/java/net/minecraft/init/Blocks.java @@ -40,7 +40,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/init/Bootstrap.java b/src/game/java/net/minecraft/init/Bootstrap.java index 00f51c08..9f3ae2b2 100755 --- a/src/game/java/net/minecraft/init/Bootstrap.java +++ b/src/game/java/net/minecraft/init/Bootstrap.java @@ -64,7 +64,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/init/Items.java b/src/game/java/net/minecraft/init/Items.java index 393c72ef..b5fcb864 100755 --- a/src/game/java/net/minecraft/init/Items.java +++ b/src/game/java/net/minecraft/init/Items.java @@ -18,7 +18,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/AnimalChest.java b/src/game/java/net/minecraft/inventory/AnimalChest.java index 8a665142..c2ffc54f 100755 --- a/src/game/java/net/minecraft/inventory/AnimalChest.java +++ b/src/game/java/net/minecraft/inventory/AnimalChest.java @@ -8,7 +8,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/Container.java b/src/game/java/net/minecraft/inventory/Container.java index 7f1019ad..45c33204 100755 --- a/src/game/java/net/minecraft/inventory/Container.java +++ b/src/game/java/net/minecraft/inventory/Container.java @@ -20,7 +20,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/ContainerBeacon.java b/src/game/java/net/minecraft/inventory/ContainerBeacon.java index c392b12a..83fcbb5a 100755 --- a/src/game/java/net/minecraft/inventory/ContainerBeacon.java +++ b/src/game/java/net/minecraft/inventory/ContainerBeacon.java @@ -10,7 +10,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/ContainerBrewingStand.java b/src/game/java/net/minecraft/inventory/ContainerBrewingStand.java index 0a27e509..259e3ca8 100755 --- a/src/game/java/net/minecraft/inventory/ContainerBrewingStand.java +++ b/src/game/java/net/minecraft/inventory/ContainerBrewingStand.java @@ -12,7 +12,7 @@ import net.minecraft.stats.AchievementList; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/ContainerChest.java b/src/game/java/net/minecraft/inventory/ContainerChest.java index 7ca236a3..93ad7be4 100755 --- a/src/game/java/net/minecraft/inventory/ContainerChest.java +++ b/src/game/java/net/minecraft/inventory/ContainerChest.java @@ -9,7 +9,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/ContainerDispenser.java b/src/game/java/net/minecraft/inventory/ContainerDispenser.java index 4f191a00..49458c4e 100755 --- a/src/game/java/net/minecraft/inventory/ContainerDispenser.java +++ b/src/game/java/net/minecraft/inventory/ContainerDispenser.java @@ -9,7 +9,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/ContainerEnchantment.java b/src/game/java/net/minecraft/inventory/ContainerEnchantment.java index bf182d0b..828e6c37 100755 --- a/src/game/java/net/minecraft/inventory/ContainerEnchantment.java +++ b/src/game/java/net/minecraft/inventory/ContainerEnchantment.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/ContainerFurnace.java b/src/game/java/net/minecraft/inventory/ContainerFurnace.java index a023a86d..b3c826f0 100755 --- a/src/game/java/net/minecraft/inventory/ContainerFurnace.java +++ b/src/game/java/net/minecraft/inventory/ContainerFurnace.java @@ -12,7 +12,7 @@ import net.minecraft.tileentity.TileEntityFurnace; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/ContainerHopper.java b/src/game/java/net/minecraft/inventory/ContainerHopper.java index 930b84bb..738b0673 100755 --- a/src/game/java/net/minecraft/inventory/ContainerHopper.java +++ b/src/game/java/net/minecraft/inventory/ContainerHopper.java @@ -10,7 +10,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/ContainerHorseInventory.java b/src/game/java/net/minecraft/inventory/ContainerHorseInventory.java index a06e0a02..44d883e0 100755 --- a/src/game/java/net/minecraft/inventory/ContainerHorseInventory.java +++ b/src/game/java/net/minecraft/inventory/ContainerHorseInventory.java @@ -11,7 +11,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/ContainerMerchant.java b/src/game/java/net/minecraft/inventory/ContainerMerchant.java index 93a71f25..c05c65e4 100755 --- a/src/game/java/net/minecraft/inventory/ContainerMerchant.java +++ b/src/game/java/net/minecraft/inventory/ContainerMerchant.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/ContainerPlayer.java b/src/game/java/net/minecraft/inventory/ContainerPlayer.java index abe951b6..0cb1ba5b 100755 --- a/src/game/java/net/minecraft/inventory/ContainerPlayer.java +++ b/src/game/java/net/minecraft/inventory/ContainerPlayer.java @@ -15,7 +15,7 @@ import net.minecraft.item.crafting.CraftingManager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/ContainerRepair.java b/src/game/java/net/minecraft/inventory/ContainerRepair.java index 62fe6843..54721966 100755 --- a/src/game/java/net/minecraft/inventory/ContainerRepair.java +++ b/src/game/java/net/minecraft/inventory/ContainerRepair.java @@ -1,7 +1,5 @@ package net.minecraft.inventory; -import java.util.Iterator; -import java.util.Map; import net.minecraft.block.BlockAnvil; import net.minecraft.block.state.IBlockState; import net.minecraft.enchantment.Enchantment; @@ -14,6 +12,11 @@ import net.minecraft.item.ItemStack; import net.minecraft.util.BlockPos; import net.minecraft.world.World; import org.apache.commons.lang3.StringUtils; + +import com.carrotsearch.hppc.IntIntMap; +import com.carrotsearch.hppc.cursors.IntCursor; +import com.carrotsearch.hppc.cursors.IntIntCursor; + import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; import net.lax1dude.eaglercraft.v1_8.log4j.Logger; @@ -23,7 +26,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -162,7 +165,7 @@ public class ContainerRepair extends Container { } else { ItemStack itemstack1 = itemstack.copy(); ItemStack itemstack2 = this.inputSlots.getStackInSlot(1); - Map map = EnchantmentHelper.getEnchantments(itemstack1); + IntIntMap map = EnchantmentHelper.getEnchantments(itemstack1); boolean flag7 = false; j = j + itemstack.getRepairCost() + (itemstack2 == null ? 0 : itemstack2.getRepairCost()); this.materialCost = 0; @@ -210,17 +213,14 @@ public class ContainerRepair extends Container { } } - Map map1 = EnchantmentHelper.getEnchantments(itemstack2); - Iterator iterator1 = map1.keySet().iterator(); + IntIntMap map1 = EnchantmentHelper.getEnchantments(itemstack2); - while (iterator1.hasNext()) { - int i3 = ((Integer) iterator1.next()).intValue(); + for (IntIntCursor cur : map1) { + int i3 = cur.key; Enchantment enchantment = Enchantment.getEnchantmentById(i3); if (enchantment != null) { - int k3 = map.containsKey(Integer.valueOf(i3)) - ? ((Integer) map.get(Integer.valueOf(i3))).intValue() - : 0; - int l1 = ((Integer) map1.get(Integer.valueOf(i3))).intValue(); + int k3 = map.getOrDefault(i3, 0); + int l1 = cur.value; int i4; if (k3 == l1) { ++l1; @@ -236,10 +236,8 @@ public class ContainerRepair extends Container { flag8 = true; } - Iterator iterator = map.keySet().iterator(); - - while (iterator.hasNext()) { - int i2 = ((Integer) iterator.next()).intValue(); + for (IntCursor curr : map.keys()) { + int i2 = curr.value; if (i2 != i3 && !enchantment.canApplyTogether(Enchantment.getEnchantmentById(i2))) { flag8 = false; ++i; @@ -251,7 +249,7 @@ public class ContainerRepair extends Container { l1 = enchantment.getMaxLevel(); } - map.put(Integer.valueOf(i3), Integer.valueOf(l1)); + map.put(i3, l1); int l3 = 0; switch (enchantment.getWeight()) { case 1: diff --git a/src/game/java/net/minecraft/inventory/ContainerWorkbench.java b/src/game/java/net/minecraft/inventory/ContainerWorkbench.java index 2959bb26..3145b52e 100755 --- a/src/game/java/net/minecraft/inventory/ContainerWorkbench.java +++ b/src/game/java/net/minecraft/inventory/ContainerWorkbench.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/ICrafting.java b/src/game/java/net/minecraft/inventory/ICrafting.java index 7fa10887..98567a59 100755 --- a/src/game/java/net/minecraft/inventory/ICrafting.java +++ b/src/game/java/net/minecraft/inventory/ICrafting.java @@ -10,7 +10,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/IInvBasic.java b/src/game/java/net/minecraft/inventory/IInvBasic.java index 35cc4276..e3fa816e 100755 --- a/src/game/java/net/minecraft/inventory/IInvBasic.java +++ b/src/game/java/net/minecraft/inventory/IInvBasic.java @@ -6,7 +6,7 @@ package net.minecraft.inventory; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/IInventory.java b/src/game/java/net/minecraft/inventory/IInventory.java index 1f126130..fa074d37 100755 --- a/src/game/java/net/minecraft/inventory/IInventory.java +++ b/src/game/java/net/minecraft/inventory/IInventory.java @@ -10,7 +10,7 @@ import net.minecraft.world.IWorldNameable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/ISidedInventory.java b/src/game/java/net/minecraft/inventory/ISidedInventory.java index 7ee51421..cbdf74b3 100755 --- a/src/game/java/net/minecraft/inventory/ISidedInventory.java +++ b/src/game/java/net/minecraft/inventory/ISidedInventory.java @@ -9,7 +9,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/InventoryBasic.java b/src/game/java/net/minecraft/inventory/InventoryBasic.java index 3fb2f412..b2b6ee89 100755 --- a/src/game/java/net/minecraft/inventory/InventoryBasic.java +++ b/src/game/java/net/minecraft/inventory/InventoryBasic.java @@ -16,7 +16,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/InventoryCraftResult.java b/src/game/java/net/minecraft/inventory/InventoryCraftResult.java index 31ac5df8..b1c045d4 100755 --- a/src/game/java/net/minecraft/inventory/InventoryCraftResult.java +++ b/src/game/java/net/minecraft/inventory/InventoryCraftResult.java @@ -12,7 +12,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/InventoryCrafting.java b/src/game/java/net/minecraft/inventory/InventoryCrafting.java index c6530349..77bea52f 100755 --- a/src/game/java/net/minecraft/inventory/InventoryCrafting.java +++ b/src/game/java/net/minecraft/inventory/InventoryCrafting.java @@ -12,7 +12,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/InventoryEnderChest.java b/src/game/java/net/minecraft/inventory/InventoryEnderChest.java index 5b714224..035aeea2 100755 --- a/src/game/java/net/minecraft/inventory/InventoryEnderChest.java +++ b/src/game/java/net/minecraft/inventory/InventoryEnderChest.java @@ -12,7 +12,7 @@ import net.minecraft.tileentity.TileEntityEnderChest; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/InventoryHelper.java b/src/game/java/net/minecraft/inventory/InventoryHelper.java index fe80d18b..d1e36bce 100755 --- a/src/game/java/net/minecraft/inventory/InventoryHelper.java +++ b/src/game/java/net/minecraft/inventory/InventoryHelper.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/InventoryLargeChest.java b/src/game/java/net/minecraft/inventory/InventoryLargeChest.java index 5874609d..18a6ba32 100755 --- a/src/game/java/net/minecraft/inventory/InventoryLargeChest.java +++ b/src/game/java/net/minecraft/inventory/InventoryLargeChest.java @@ -15,7 +15,7 @@ import net.minecraft.world.LockCode; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/InventoryMerchant.java b/src/game/java/net/minecraft/inventory/InventoryMerchant.java index 0a69fa28..fc772f4f 100755 --- a/src/game/java/net/minecraft/inventory/InventoryMerchant.java +++ b/src/game/java/net/minecraft/inventory/InventoryMerchant.java @@ -15,7 +15,7 @@ import net.minecraft.village.MerchantRecipeList; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/Slot.java b/src/game/java/net/minecraft/inventory/Slot.java index aa0aa00a..1f4d3030 100755 --- a/src/game/java/net/minecraft/inventory/Slot.java +++ b/src/game/java/net/minecraft/inventory/Slot.java @@ -9,7 +9,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/SlotCrafting.java b/src/game/java/net/minecraft/inventory/SlotCrafting.java index 6bea63f9..a139cea7 100755 --- a/src/game/java/net/minecraft/inventory/SlotCrafting.java +++ b/src/game/java/net/minecraft/inventory/SlotCrafting.java @@ -17,7 +17,7 @@ import net.minecraft.stats.AchievementList; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/SlotFurnaceFuel.java b/src/game/java/net/minecraft/inventory/SlotFurnaceFuel.java index 822e37cf..79e7d752 100755 --- a/src/game/java/net/minecraft/inventory/SlotFurnaceFuel.java +++ b/src/game/java/net/minecraft/inventory/SlotFurnaceFuel.java @@ -10,7 +10,7 @@ import net.minecraft.tileentity.TileEntityFurnace; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/SlotFurnaceOutput.java b/src/game/java/net/minecraft/inventory/SlotFurnaceOutput.java index e8561208..48094918 100755 --- a/src/game/java/net/minecraft/inventory/SlotFurnaceOutput.java +++ b/src/game/java/net/minecraft/inventory/SlotFurnaceOutput.java @@ -14,7 +14,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/inventory/SlotMerchantResult.java b/src/game/java/net/minecraft/inventory/SlotMerchantResult.java index af69b41f..e9ed4dff 100755 --- a/src/game/java/net/minecraft/inventory/SlotMerchantResult.java +++ b/src/game/java/net/minecraft/inventory/SlotMerchantResult.java @@ -12,7 +12,7 @@ import net.minecraft.village.MerchantRecipe; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/EnumAction.java b/src/game/java/net/minecraft/item/EnumAction.java index 787ebec3..f2c2c71a 100755 --- a/src/game/java/net/minecraft/item/EnumAction.java +++ b/src/game/java/net/minecraft/item/EnumAction.java @@ -6,7 +6,7 @@ package net.minecraft.item; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/EnumDyeColor.java b/src/game/java/net/minecraft/item/EnumDyeColor.java index 322082f3..94cb7bb3 100755 --- a/src/game/java/net/minecraft/item/EnumDyeColor.java +++ b/src/game/java/net/minecraft/item/EnumDyeColor.java @@ -10,7 +10,7 @@ import net.minecraft.util.IStringSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/EnumRarity.java b/src/game/java/net/minecraft/item/EnumRarity.java index f503cbd4..00803cd3 100755 --- a/src/game/java/net/minecraft/item/EnumRarity.java +++ b/src/game/java/net/minecraft/item/EnumRarity.java @@ -8,7 +8,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/Item.java b/src/game/java/net/minecraft/item/Item.java index 15f73165..80d0b25a 100755 --- a/src/game/java/net/minecraft/item/Item.java +++ b/src/game/java/net/minecraft/item/Item.java @@ -52,7 +52,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemAnvilBlock.java b/src/game/java/net/minecraft/item/ItemAnvilBlock.java index 6a0b5fab..cea0ecb7 100755 --- a/src/game/java/net/minecraft/item/ItemAnvilBlock.java +++ b/src/game/java/net/minecraft/item/ItemAnvilBlock.java @@ -8,7 +8,7 @@ import net.minecraft.block.Block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemAppleGold.java b/src/game/java/net/minecraft/item/ItemAppleGold.java index 68b91c44..b3860021 100755 --- a/src/game/java/net/minecraft/item/ItemAppleGold.java +++ b/src/game/java/net/minecraft/item/ItemAppleGold.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemArmor.java b/src/game/java/net/minecraft/item/ItemArmor.java index a2fb46c9..f9877643 100755 --- a/src/game/java/net/minecraft/item/ItemArmor.java +++ b/src/game/java/net/minecraft/item/ItemArmor.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemArmorStand.java b/src/game/java/net/minecraft/item/ItemArmorStand.java index 22d8342a..2fbc0c66 100755 --- a/src/game/java/net/minecraft/item/ItemArmorStand.java +++ b/src/game/java/net/minecraft/item/ItemArmorStand.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemAxe.java b/src/game/java/net/minecraft/item/ItemAxe.java index 08c39c9c..0e08bcff 100755 --- a/src/game/java/net/minecraft/item/ItemAxe.java +++ b/src/game/java/net/minecraft/item/ItemAxe.java @@ -14,7 +14,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemBanner.java b/src/game/java/net/minecraft/item/ItemBanner.java index 06ab518e..9ee5a9ed 100755 --- a/src/game/java/net/minecraft/item/ItemBanner.java +++ b/src/game/java/net/minecraft/item/ItemBanner.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemBed.java b/src/game/java/net/minecraft/item/ItemBed.java index 991e1eb2..f550803f 100755 --- a/src/game/java/net/minecraft/item/ItemBed.java +++ b/src/game/java/net/minecraft/item/ItemBed.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemBlock.java b/src/game/java/net/minecraft/item/ItemBlock.java index c6411ee0..d4370628 100755 --- a/src/game/java/net/minecraft/item/ItemBlock.java +++ b/src/game/java/net/minecraft/item/ItemBlock.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemBoat.java b/src/game/java/net/minecraft/item/ItemBoat.java index d71c7084..5671a329 100755 --- a/src/game/java/net/minecraft/item/ItemBoat.java +++ b/src/game/java/net/minecraft/item/ItemBoat.java @@ -21,7 +21,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemBook.java b/src/game/java/net/minecraft/item/ItemBook.java index b2ce15a3..5b4a1a67 100755 --- a/src/game/java/net/minecraft/item/ItemBook.java +++ b/src/game/java/net/minecraft/item/ItemBook.java @@ -6,7 +6,7 @@ package net.minecraft.item; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemBow.java b/src/game/java/net/minecraft/item/ItemBow.java index b6e9a142..96edb844 100755 --- a/src/game/java/net/minecraft/item/ItemBow.java +++ b/src/game/java/net/minecraft/item/ItemBow.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemBucket.java b/src/game/java/net/minecraft/item/ItemBucket.java index 20690290..82a55620 100755 --- a/src/game/java/net/minecraft/item/ItemBucket.java +++ b/src/game/java/net/minecraft/item/ItemBucket.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemBucketMilk.java b/src/game/java/net/minecraft/item/ItemBucketMilk.java index 79247e16..6f2f2ae5 100755 --- a/src/game/java/net/minecraft/item/ItemBucketMilk.java +++ b/src/game/java/net/minecraft/item/ItemBucketMilk.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemCarrotOnAStick.java b/src/game/java/net/minecraft/item/ItemCarrotOnAStick.java index 30873bf0..cc88be0d 100755 --- a/src/game/java/net/minecraft/item/ItemCarrotOnAStick.java +++ b/src/game/java/net/minecraft/item/ItemCarrotOnAStick.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemCloth.java b/src/game/java/net/minecraft/item/ItemCloth.java index e70b5f70..9c5f982c 100755 --- a/src/game/java/net/minecraft/item/ItemCloth.java +++ b/src/game/java/net/minecraft/item/ItemCloth.java @@ -8,7 +8,7 @@ import net.minecraft.block.Block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemCoal.java b/src/game/java/net/minecraft/item/ItemCoal.java index fce3b2e4..005f5fdb 100755 --- a/src/game/java/net/minecraft/item/ItemCoal.java +++ b/src/game/java/net/minecraft/item/ItemCoal.java @@ -10,7 +10,7 @@ import net.minecraft.creativetab.CreativeTabs; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemColored.java b/src/game/java/net/minecraft/item/ItemColored.java index 750fb31b..d2dc1848 100755 --- a/src/game/java/net/minecraft/item/ItemColored.java +++ b/src/game/java/net/minecraft/item/ItemColored.java @@ -8,7 +8,7 @@ import net.minecraft.block.Block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemDoor.java b/src/game/java/net/minecraft/item/ItemDoor.java index 9e641a1c..07c445c4 100755 --- a/src/game/java/net/minecraft/item/ItemDoor.java +++ b/src/game/java/net/minecraft/item/ItemDoor.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemDoublePlant.java b/src/game/java/net/minecraft/item/ItemDoublePlant.java index 7ab3cc4e..d7dcd8d4 100755 --- a/src/game/java/net/minecraft/item/ItemDoublePlant.java +++ b/src/game/java/net/minecraft/item/ItemDoublePlant.java @@ -12,7 +12,7 @@ import net.minecraft.world.ColorizerGrass; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemDye.java b/src/game/java/net/minecraft/item/ItemDye.java index 9d7054e5..2339a64e 100755 --- a/src/game/java/net/minecraft/item/ItemDye.java +++ b/src/game/java/net/minecraft/item/ItemDye.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemEditableBook.java b/src/game/java/net/minecraft/item/ItemEditableBook.java index b36a50bc..0ec5ef35 100755 --- a/src/game/java/net/minecraft/item/ItemEditableBook.java +++ b/src/game/java/net/minecraft/item/ItemEditableBook.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemEgg.java b/src/game/java/net/minecraft/item/ItemEgg.java index c4644a7b..e11b31d1 100755 --- a/src/game/java/net/minecraft/item/ItemEgg.java +++ b/src/game/java/net/minecraft/item/ItemEgg.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemEmptyMap.java b/src/game/java/net/minecraft/item/ItemEmptyMap.java index 31db0284..b8ab220a 100755 --- a/src/game/java/net/minecraft/item/ItemEmptyMap.java +++ b/src/game/java/net/minecraft/item/ItemEmptyMap.java @@ -13,7 +13,7 @@ import net.minecraft.world.storage.MapData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemEnchantedBook.java b/src/game/java/net/minecraft/item/ItemEnchantedBook.java index 2fae3e0b..4a978880 100755 --- a/src/game/java/net/minecraft/item/ItemEnchantedBook.java +++ b/src/game/java/net/minecraft/item/ItemEnchantedBook.java @@ -18,7 +18,7 @@ import net.minecraft.util.WeightedRandomChestContent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemEnderEye.java b/src/game/java/net/minecraft/item/ItemEnderEye.java index caf2d753..1deee295 100755 --- a/src/game/java/net/minecraft/item/ItemEnderEye.java +++ b/src/game/java/net/minecraft/item/ItemEnderEye.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemEnderPearl.java b/src/game/java/net/minecraft/item/ItemEnderPearl.java index db9b2688..3fd2a7ca 100755 --- a/src/game/java/net/minecraft/item/ItemEnderPearl.java +++ b/src/game/java/net/minecraft/item/ItemEnderPearl.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemExpBottle.java b/src/game/java/net/minecraft/item/ItemExpBottle.java index 1c03ac28..bfacc3f3 100755 --- a/src/game/java/net/minecraft/item/ItemExpBottle.java +++ b/src/game/java/net/minecraft/item/ItemExpBottle.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemFireball.java b/src/game/java/net/minecraft/item/ItemFireball.java index d4830404..7dc866ac 100755 --- a/src/game/java/net/minecraft/item/ItemFireball.java +++ b/src/game/java/net/minecraft/item/ItemFireball.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemFirework.java b/src/game/java/net/minecraft/item/ItemFirework.java index bf68ec4b..f6d24d9a 100755 --- a/src/game/java/net/minecraft/item/ItemFirework.java +++ b/src/game/java/net/minecraft/item/ItemFirework.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemFireworkCharge.java b/src/game/java/net/minecraft/item/ItemFireworkCharge.java index 94bf912a..d6799278 100755 --- a/src/game/java/net/minecraft/item/ItemFireworkCharge.java +++ b/src/game/java/net/minecraft/item/ItemFireworkCharge.java @@ -14,7 +14,7 @@ import net.minecraft.util.StatCollector; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemFishFood.java b/src/game/java/net/minecraft/item/ItemFishFood.java index 073a2aa6..b43e8593 100755 --- a/src/game/java/net/minecraft/item/ItemFishFood.java +++ b/src/game/java/net/minecraft/item/ItemFishFood.java @@ -1,9 +1,9 @@ package net.minecraft.item; import java.util.List; -import java.util.Map; -import com.google.common.collect.Maps; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.player.EntityPlayer; @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -99,7 +99,7 @@ public class ItemFishFood extends ItemFood { COD(0, "cod", 2, 0.1F, 5, 0.6F), SALMON(1, "salmon", 2, 0.1F, 6, 0.8F), CLOWNFISH(2, "clownfish", 1, 0.1F), PUFFERFISH(3, "pufferfish", 1, 0.1F); - private static final Map META_LOOKUP = Maps.newHashMap(); + private static final IntObjectMap META_LOOKUP = new IntObjectHashMap<>(); private final int meta; private final String unlocalizedName; private final int uncookedHealAmount; @@ -163,8 +163,7 @@ public class ItemFishFood extends ItemFood { } public static ItemFishFood.FishType byMetadata(int meta) { - ItemFishFood.FishType itemfishfood$fishtype = (ItemFishFood.FishType) META_LOOKUP - .get(Integer.valueOf(meta)); + ItemFishFood.FishType itemfishfood$fishtype = META_LOOKUP.get(meta); return itemfishfood$fishtype == null ? COD : itemfishfood$fishtype; } @@ -175,7 +174,7 @@ public class ItemFishFood extends ItemFood { static { ItemFishFood.FishType[] types = values(); for (int i = 0; i < types.length; ++i) { - META_LOOKUP.put(Integer.valueOf(types[i].getMetadata()), types[i]); + META_LOOKUP.put(types[i].getMetadata(), types[i]); } } diff --git a/src/game/java/net/minecraft/item/ItemFishingRod.java b/src/game/java/net/minecraft/item/ItemFishingRod.java index 90892851..8478a744 100755 --- a/src/game/java/net/minecraft/item/ItemFishingRod.java +++ b/src/game/java/net/minecraft/item/ItemFishingRod.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemFlintAndSteel.java b/src/game/java/net/minecraft/item/ItemFlintAndSteel.java index 09116cb6..fecfc831 100755 --- a/src/game/java/net/minecraft/item/ItemFlintAndSteel.java +++ b/src/game/java/net/minecraft/item/ItemFlintAndSteel.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemFood.java b/src/game/java/net/minecraft/item/ItemFood.java index f99eaf7b..5c62482d 100755 --- a/src/game/java/net/minecraft/item/ItemFood.java +++ b/src/game/java/net/minecraft/item/ItemFood.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemGlassBottle.java b/src/game/java/net/minecraft/item/ItemGlassBottle.java index ff35eff9..78d9d2a2 100755 --- a/src/game/java/net/minecraft/item/ItemGlassBottle.java +++ b/src/game/java/net/minecraft/item/ItemGlassBottle.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemHangingEntity.java b/src/game/java/net/minecraft/item/ItemHangingEntity.java index bf94339f..50021c71 100755 --- a/src/game/java/net/minecraft/item/ItemHangingEntity.java +++ b/src/game/java/net/minecraft/item/ItemHangingEntity.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemHoe.java b/src/game/java/net/minecraft/item/ItemHoe.java index 87d9af89..607d291f 100755 --- a/src/game/java/net/minecraft/item/ItemHoe.java +++ b/src/game/java/net/minecraft/item/ItemHoe.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemLead.java b/src/game/java/net/minecraft/item/ItemLead.java index b82c5230..b830db6d 100755 --- a/src/game/java/net/minecraft/item/ItemLead.java +++ b/src/game/java/net/minecraft/item/ItemLead.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemLeaves.java b/src/game/java/net/minecraft/item/ItemLeaves.java index 9bf4508d..28f27732 100755 --- a/src/game/java/net/minecraft/item/ItemLeaves.java +++ b/src/game/java/net/minecraft/item/ItemLeaves.java @@ -8,7 +8,7 @@ import net.minecraft.block.BlockLeaves; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemLilyPad.java b/src/game/java/net/minecraft/item/ItemLilyPad.java index 4410eddc..574d6cdf 100755 --- a/src/game/java/net/minecraft/item/ItemLilyPad.java +++ b/src/game/java/net/minecraft/item/ItemLilyPad.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemMap.java b/src/game/java/net/minecraft/item/ItemMap.java index fa3a7a12..84c84561 100755 --- a/src/game/java/net/minecraft/item/ItemMap.java +++ b/src/game/java/net/minecraft/item/ItemMap.java @@ -28,7 +28,7 @@ import net.minecraft.world.storage.MapData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemMapBase.java b/src/game/java/net/minecraft/item/ItemMapBase.java index 52e2f61c..3dbaee81 100755 --- a/src/game/java/net/minecraft/item/ItemMapBase.java +++ b/src/game/java/net/minecraft/item/ItemMapBase.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemMinecart.java b/src/game/java/net/minecraft/item/ItemMinecart.java index 2047d9cf..54e7449b 100755 --- a/src/game/java/net/minecraft/item/ItemMinecart.java +++ b/src/game/java/net/minecraft/item/ItemMinecart.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemMonsterPlacer.java b/src/game/java/net/minecraft/item/ItemMonsterPlacer.java index 4862159f..dfb5059d 100755 --- a/src/game/java/net/minecraft/item/ItemMonsterPlacer.java +++ b/src/game/java/net/minecraft/item/ItemMonsterPlacer.java @@ -1,6 +1,9 @@ package net.minecraft.item; import java.util.List; + +import com.carrotsearch.hppc.cursors.ObjectCursor; + import net.minecraft.block.BlockFence; import net.minecraft.block.BlockLiquid; import net.minecraft.block.state.IBlockState; @@ -29,7 +32,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -195,8 +198,8 @@ public class ItemMonsterPlacer extends Item { * (eg: dye returns 16 items) */ public void getSubItems(Item item, CreativeTabs var2, List list) { - for (EntityList.EntityEggInfo entitylist$entityegginfo : EntityList.entityEggs.values()) { - list.add(new ItemStack(item, 1, entitylist$entityegginfo.spawnedID)); + for (ObjectCursor entitylist$entityegginfo : EntityList.entityEggs.values()) { + list.add(new ItemStack(item, 1, entitylist$entityegginfo.value.spawnedID)); } } diff --git a/src/game/java/net/minecraft/item/ItemMultiTexture.java b/src/game/java/net/minecraft/item/ItemMultiTexture.java index e4ef15f8..aa10a669 100755 --- a/src/game/java/net/minecraft/item/ItemMultiTexture.java +++ b/src/game/java/net/minecraft/item/ItemMultiTexture.java @@ -10,7 +10,7 @@ import net.minecraft.block.Block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemNameTag.java b/src/game/java/net/minecraft/item/ItemNameTag.java index 0c1969ff..ce58fd4b 100755 --- a/src/game/java/net/minecraft/item/ItemNameTag.java +++ b/src/game/java/net/minecraft/item/ItemNameTag.java @@ -11,7 +11,7 @@ import net.minecraft.entity.player.EntityPlayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemPickaxe.java b/src/game/java/net/minecraft/item/ItemPickaxe.java index 08b3cb45..62c034e0 100755 --- a/src/game/java/net/minecraft/item/ItemPickaxe.java +++ b/src/game/java/net/minecraft/item/ItemPickaxe.java @@ -14,7 +14,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemPiston.java b/src/game/java/net/minecraft/item/ItemPiston.java index 6187cefc..e59cd2d3 100755 --- a/src/game/java/net/minecraft/item/ItemPiston.java +++ b/src/game/java/net/minecraft/item/ItemPiston.java @@ -8,7 +8,7 @@ import net.minecraft.block.Block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemPotion.java b/src/game/java/net/minecraft/item/ItemPotion.java index 05b4f03f..e6e134ee 100755 --- a/src/game/java/net/minecraft/item/ItemPotion.java +++ b/src/game/java/net/minecraft/item/ItemPotion.java @@ -1,15 +1,18 @@ package net.minecraft.item; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; +import com.carrotsearch.hppc.ObjectIntHashMap; +import com.carrotsearch.hppc.ObjectIntMap; +import com.carrotsearch.hppc.cursors.IntCursor; import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.ai.attributes.AttributeModifier; @@ -33,7 +36,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -48,8 +51,13 @@ import net.minecraft.world.World; * */ public class ItemPotion extends Item { - private Map> effectCache = Maps.newHashMap(); - private static final Map, Integer> SUB_ITEMS_CACHE = Maps.newLinkedHashMap(); + /**+ + * Contains a map from integers to the list of potion effects + * that potions with that damage value confer (to prevent + * recalculating it). + */ + private IntObjectMap> effectCache = new IntObjectHashMap<>(); + private static final ObjectIntMap> SUB_ITEMS_CACHE = new ObjectIntHashMap<>(); public ItemPotion() { this.setMaxStackSize(1); @@ -77,10 +85,10 @@ public class ItemPotion extends Item { return arraylist; } else { - List list = (List) this.effectCache.get(Integer.valueOf(stack.getMetadata())); + List list = this.effectCache.get(stack.getMetadata()); if (list == null) { list = PotionHelper.getPotionEffects(stack.getMetadata(), false); - this.effectCache.put(Integer.valueOf(stack.getMetadata()), list); + this.effectCache.put(stack.getMetadata(), list); } return list; @@ -92,10 +100,10 @@ public class ItemPotion extends Item { * value. */ public List getEffects(int meta) { - List list = (List) this.effectCache.get(Integer.valueOf(meta)); + List list = this.effectCache.get(meta); if (list == null) { list = PotionHelper.getPotionEffects(meta, false); - this.effectCache.put(Integer.valueOf(meta), list); + this.effectCache.put(meta, list); } return list; @@ -332,18 +340,15 @@ public class ItemPotion extends Item { List list = PotionHelper.getPotionEffects(i1, false); if (list != null && !list.isEmpty()) { - SUB_ITEMS_CACHE.put(list, Integer.valueOf(i1)); + SUB_ITEMS_CACHE.put(list, i1); } } } } } - Iterator iterator = SUB_ITEMS_CACHE.values().iterator(); - - while (iterator.hasNext()) { - int j1 = ((Integer) iterator.next()).intValue(); - subItems.add(new ItemStack(itemIn, 1, j1)); + for (IntCursor cur : SUB_ITEMS_CACHE.values()) { + subItems.add(new ItemStack(itemIn, 1, cur.value)); } } diff --git a/src/game/java/net/minecraft/item/ItemRecord.java b/src/game/java/net/minecraft/item/ItemRecord.java index cf269441..f97fbb6e 100755 --- a/src/game/java/net/minecraft/item/ItemRecord.java +++ b/src/game/java/net/minecraft/item/ItemRecord.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemRedstone.java b/src/game/java/net/minecraft/item/ItemRedstone.java index c1d6a1c6..40e0fae7 100755 --- a/src/game/java/net/minecraft/item/ItemRedstone.java +++ b/src/game/java/net/minecraft/item/ItemRedstone.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemReed.java b/src/game/java/net/minecraft/item/ItemReed.java index 6da64a94..d6a002dc 100755 --- a/src/game/java/net/minecraft/item/ItemReed.java +++ b/src/game/java/net/minecraft/item/ItemReed.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemSaddle.java b/src/game/java/net/minecraft/item/ItemSaddle.java index e55b3f3d..6c327383 100755 --- a/src/game/java/net/minecraft/item/ItemSaddle.java +++ b/src/game/java/net/minecraft/item/ItemSaddle.java @@ -11,7 +11,7 @@ import net.minecraft.entity.player.EntityPlayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemSeedFood.java b/src/game/java/net/minecraft/item/ItemSeedFood.java index f815487b..bd8c4260 100755 --- a/src/game/java/net/minecraft/item/ItemSeedFood.java +++ b/src/game/java/net/minecraft/item/ItemSeedFood.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemSeeds.java b/src/game/java/net/minecraft/item/ItemSeeds.java index a6c70e31..de10bda7 100755 --- a/src/game/java/net/minecraft/item/ItemSeeds.java +++ b/src/game/java/net/minecraft/item/ItemSeeds.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemShears.java b/src/game/java/net/minecraft/item/ItemShears.java index f5f154fb..69a9e8e6 100755 --- a/src/game/java/net/minecraft/item/ItemShears.java +++ b/src/game/java/net/minecraft/item/ItemShears.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemSign.java b/src/game/java/net/minecraft/item/ItemSign.java index 3056f68a..c8138b64 100755 --- a/src/game/java/net/minecraft/item/ItemSign.java +++ b/src/game/java/net/minecraft/item/ItemSign.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemSimpleFoiled.java b/src/game/java/net/minecraft/item/ItemSimpleFoiled.java index 337b804f..34c20e5b 100755 --- a/src/game/java/net/minecraft/item/ItemSimpleFoiled.java +++ b/src/game/java/net/minecraft/item/ItemSimpleFoiled.java @@ -6,7 +6,7 @@ package net.minecraft.item; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemSkull.java b/src/game/java/net/minecraft/item/ItemSkull.java index 9c7b9f84..b53c1f30 100755 --- a/src/game/java/net/minecraft/item/ItemSkull.java +++ b/src/game/java/net/minecraft/item/ItemSkull.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemSlab.java b/src/game/java/net/minecraft/item/ItemSlab.java index c218aeaa..a3ee35b2 100755 --- a/src/game/java/net/minecraft/item/ItemSlab.java +++ b/src/game/java/net/minecraft/item/ItemSlab.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemSnow.java b/src/game/java/net/minecraft/item/ItemSnow.java index 2ca8cc47..f32575f6 100755 --- a/src/game/java/net/minecraft/item/ItemSnow.java +++ b/src/game/java/net/minecraft/item/ItemSnow.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemSnowball.java b/src/game/java/net/minecraft/item/ItemSnowball.java index ff344c64..4ca3730f 100755 --- a/src/game/java/net/minecraft/item/ItemSnowball.java +++ b/src/game/java/net/minecraft/item/ItemSnowball.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemSoup.java b/src/game/java/net/minecraft/item/ItemSoup.java index 81f01a99..591990e9 100755 --- a/src/game/java/net/minecraft/item/ItemSoup.java +++ b/src/game/java/net/minecraft/item/ItemSoup.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemSpade.java b/src/game/java/net/minecraft/item/ItemSpade.java index 490ba7ae..4fdff6e8 100755 --- a/src/game/java/net/minecraft/item/ItemSpade.java +++ b/src/game/java/net/minecraft/item/ItemSpade.java @@ -13,7 +13,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemStack.java b/src/game/java/net/minecraft/item/ItemStack.java index d88d161e..41e4ec63 100755 --- a/src/game/java/net/minecraft/item/ItemStack.java +++ b/src/game/java/net/minecraft/item/ItemStack.java @@ -47,7 +47,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemSword.java b/src/game/java/net/minecraft/item/ItemSword.java index b6df2591..e74c5e14 100755 --- a/src/game/java/net/minecraft/item/ItemSword.java +++ b/src/game/java/net/minecraft/item/ItemSword.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemTool.java b/src/game/java/net/minecraft/item/ItemTool.java index ba81ebf4..612b3174 100755 --- a/src/game/java/net/minecraft/item/ItemTool.java +++ b/src/game/java/net/minecraft/item/ItemTool.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/ItemWritableBook.java b/src/game/java/net/minecraft/item/ItemWritableBook.java index af13fb3b..e59ff446 100755 --- a/src/game/java/net/minecraft/item/ItemWritableBook.java +++ b/src/game/java/net/minecraft/item/ItemWritableBook.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/crafting/CraftingManager.java b/src/game/java/net/minecraft/item/crafting/CraftingManager.java index 14055512..9a9f8484 100755 --- a/src/game/java/net/minecraft/item/crafting/CraftingManager.java +++ b/src/game/java/net/minecraft/item/crafting/CraftingManager.java @@ -29,7 +29,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/crafting/FurnaceRecipes.java b/src/game/java/net/minecraft/item/crafting/FurnaceRecipes.java index 17439ca0..c305fd5b 100755 --- a/src/game/java/net/minecraft/item/crafting/FurnaceRecipes.java +++ b/src/game/java/net/minecraft/item/crafting/FurnaceRecipes.java @@ -3,6 +3,9 @@ package net.minecraft.item.crafting; import java.util.Map; import java.util.Map.Entry; +import com.carrotsearch.hppc.ObjectFloatHashMap; +import com.carrotsearch.hppc.ObjectFloatMap; +import com.carrotsearch.hppc.cursors.ObjectFloatCursor; import com.google.common.collect.Maps; import net.minecraft.block.Block; @@ -20,7 +23,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -37,7 +40,11 @@ import net.minecraft.item.ItemStack; public class FurnaceRecipes { private static FurnaceRecipes smeltingBase; private Map smeltingList = Maps.newHashMap(); - private Map experienceList = Maps.newHashMap(); + /**+ + * A list which contains how many experience points each recipe + * output will give. + */ + private ObjectFloatMap experienceList = new ObjectFloatHashMap<>(); /**+ * Returns an instance of FurnaceRecipes. @@ -110,7 +117,7 @@ public class FurnaceRecipes { */ public void addSmeltingRecipe(ItemStack input, ItemStack stack, float experience) { this.smeltingList.put(input, stack); - this.experienceList.put(stack, Float.valueOf(experience)); + this.experienceList.put(stack, experience); } /**+ @@ -140,9 +147,9 @@ public class FurnaceRecipes { } public float getSmeltingExperience(ItemStack stack) { - for (Entry entry : this.experienceList.entrySet()) { - if (this.compareItemStacks(stack, (ItemStack) entry.getKey())) { - return ((Float) entry.getValue()).floatValue(); + for (ObjectFloatCursor entry : this.experienceList) { + if (this.compareItemStacks(stack, entry.key)) { + return entry.value; } } diff --git a/src/game/java/net/minecraft/item/crafting/IRecipe.java b/src/game/java/net/minecraft/item/crafting/IRecipe.java index 7ba88803..c8bf80e9 100755 --- a/src/game/java/net/minecraft/item/crafting/IRecipe.java +++ b/src/game/java/net/minecraft/item/crafting/IRecipe.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/crafting/RecipeBookCloning.java b/src/game/java/net/minecraft/item/crafting/RecipeBookCloning.java index 49988652..08d0c889 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipeBookCloning.java +++ b/src/game/java/net/minecraft/item/crafting/RecipeBookCloning.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/crafting/RecipeFireworks.java b/src/game/java/net/minecraft/item/crafting/RecipeFireworks.java index 81dea9b5..2015e043 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipeFireworks.java +++ b/src/game/java/net/minecraft/item/crafting/RecipeFireworks.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/crafting/RecipeRepairItem.java b/src/game/java/net/minecraft/item/crafting/RecipeRepairItem.java index b20045b7..fa50c951 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipeRepairItem.java +++ b/src/game/java/net/minecraft/item/crafting/RecipeRepairItem.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/crafting/RecipesArmor.java b/src/game/java/net/minecraft/item/crafting/RecipesArmor.java index f42ac617..c794e7af 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesArmor.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesArmor.java @@ -10,7 +10,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/crafting/RecipesArmorDyes.java b/src/game/java/net/minecraft/item/crafting/RecipesArmorDyes.java index d2247fba..6fa7fcbb 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesArmorDyes.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesArmorDyes.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/crafting/RecipesBanners.java b/src/game/java/net/minecraft/item/crafting/RecipesBanners.java index d8e00de0..344c80ec 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesBanners.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesBanners.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/crafting/RecipesCrafting.java b/src/game/java/net/minecraft/item/crafting/RecipesCrafting.java index c40e60f1..223b677c 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesCrafting.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesCrafting.java @@ -21,7 +21,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/crafting/RecipesDyes.java b/src/game/java/net/minecraft/item/crafting/RecipesDyes.java index a208dd5e..307e73c5 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesDyes.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesDyes.java @@ -14,7 +14,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/crafting/RecipesFood.java b/src/game/java/net/minecraft/item/crafting/RecipesFood.java index 0a56418a..4a4b124b 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesFood.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesFood.java @@ -11,7 +11,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/crafting/RecipesIngots.java b/src/game/java/net/minecraft/item/crafting/RecipesIngots.java index b406b860..f36a27a5 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesIngots.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesIngots.java @@ -12,7 +12,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/crafting/RecipesMapCloning.java b/src/game/java/net/minecraft/item/crafting/RecipesMapCloning.java index 75a475c3..a212ab33 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesMapCloning.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesMapCloning.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/crafting/RecipesMapExtending.java b/src/game/java/net/minecraft/item/crafting/RecipesMapExtending.java index 65b0f57f..0e7451fc 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesMapExtending.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesMapExtending.java @@ -13,7 +13,7 @@ import net.minecraft.world.storage.MapData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/crafting/RecipesTools.java b/src/game/java/net/minecraft/item/crafting/RecipesTools.java index a78b53c0..988b8d34 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesTools.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesTools.java @@ -11,7 +11,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/crafting/RecipesWeapons.java b/src/game/java/net/minecraft/item/crafting/RecipesWeapons.java index 3302c338..eec823ed 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesWeapons.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesWeapons.java @@ -11,7 +11,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/crafting/ShapedRecipes.java b/src/game/java/net/minecraft/item/crafting/ShapedRecipes.java index e1be923f..ca753d11 100755 --- a/src/game/java/net/minecraft/item/crafting/ShapedRecipes.java +++ b/src/game/java/net/minecraft/item/crafting/ShapedRecipes.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/item/crafting/ShapelessRecipes.java b/src/game/java/net/minecraft/item/crafting/ShapelessRecipes.java index e085b0b3..c7b7a089 100755 --- a/src/game/java/net/minecraft/item/crafting/ShapelessRecipes.java +++ b/src/game/java/net/minecraft/item/crafting/ShapelessRecipes.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/nbt/CompressedStreamTools.java b/src/game/java/net/minecraft/nbt/CompressedStreamTools.java index 1ba84a0e..298595a4 100755 --- a/src/game/java/net/minecraft/nbt/CompressedStreamTools.java +++ b/src/game/java/net/minecraft/nbt/CompressedStreamTools.java @@ -21,7 +21,7 @@ import net.minecraft.util.ReportedException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/nbt/JsonToNBT.java b/src/game/java/net/minecraft/nbt/JsonToNBT.java index a4efcd63..712e9f20 100755 --- a/src/game/java/net/minecraft/nbt/JsonToNBT.java +++ b/src/game/java/net/minecraft/nbt/JsonToNBT.java @@ -16,7 +16,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/nbt/NBTBase.java b/src/game/java/net/minecraft/nbt/NBTBase.java index f3c59fef..6d6c7e7c 100755 --- a/src/game/java/net/minecraft/nbt/NBTBase.java +++ b/src/game/java/net/minecraft/nbt/NBTBase.java @@ -10,7 +10,7 @@ import java.io.IOException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/nbt/NBTException.java b/src/game/java/net/minecraft/nbt/NBTException.java index 7ea34529..77e527b6 100755 --- a/src/game/java/net/minecraft/nbt/NBTException.java +++ b/src/game/java/net/minecraft/nbt/NBTException.java @@ -6,7 +6,7 @@ package net.minecraft.nbt; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/nbt/NBTSizeTracker.java b/src/game/java/net/minecraft/nbt/NBTSizeTracker.java index 14feda88..7f2e0c8a 100755 --- a/src/game/java/net/minecraft/nbt/NBTSizeTracker.java +++ b/src/game/java/net/minecraft/nbt/NBTSizeTracker.java @@ -6,7 +6,7 @@ package net.minecraft.nbt; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/nbt/NBTTagByte.java b/src/game/java/net/minecraft/nbt/NBTTagByte.java index 40ca4064..30d107fe 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagByte.java +++ b/src/game/java/net/minecraft/nbt/NBTTagByte.java @@ -10,7 +10,7 @@ import java.io.IOException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/nbt/NBTTagByteArray.java b/src/game/java/net/minecraft/nbt/NBTTagByteArray.java index 63738bf5..f1fae8ae 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagByteArray.java +++ b/src/game/java/net/minecraft/nbt/NBTTagByteArray.java @@ -11,7 +11,7 @@ import java.util.Arrays; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/nbt/NBTTagCompound.java b/src/game/java/net/minecraft/nbt/NBTTagCompound.java index 87fed617..5c12daac 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagCompound.java +++ b/src/game/java/net/minecraft/nbt/NBTTagCompound.java @@ -20,7 +20,7 @@ import net.minecraft.util.ReportedException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/nbt/NBTTagDouble.java b/src/game/java/net/minecraft/nbt/NBTTagDouble.java index 711b8f4e..c6d73d44 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagDouble.java +++ b/src/game/java/net/minecraft/nbt/NBTTagDouble.java @@ -12,7 +12,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/nbt/NBTTagEnd.java b/src/game/java/net/minecraft/nbt/NBTTagEnd.java index 555a32aa..607418f4 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagEnd.java +++ b/src/game/java/net/minecraft/nbt/NBTTagEnd.java @@ -10,7 +10,7 @@ import java.io.IOException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/nbt/NBTTagFloat.java b/src/game/java/net/minecraft/nbt/NBTTagFloat.java index 68284e1d..1e4c0cfb 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagFloat.java +++ b/src/game/java/net/minecraft/nbt/NBTTagFloat.java @@ -12,7 +12,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/nbt/NBTTagInt.java b/src/game/java/net/minecraft/nbt/NBTTagInt.java index e63ede6d..62a11c8f 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagInt.java +++ b/src/game/java/net/minecraft/nbt/NBTTagInt.java @@ -10,7 +10,7 @@ import java.io.IOException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/nbt/NBTTagIntArray.java b/src/game/java/net/minecraft/nbt/NBTTagIntArray.java index 8432ba50..6fa27750 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagIntArray.java +++ b/src/game/java/net/minecraft/nbt/NBTTagIntArray.java @@ -11,7 +11,7 @@ import java.util.Arrays; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/nbt/NBTTagList.java b/src/game/java/net/minecraft/nbt/NBTTagList.java index b3853d04..a578f758 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagList.java +++ b/src/game/java/net/minecraft/nbt/NBTTagList.java @@ -16,7 +16,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/nbt/NBTTagLong.java b/src/game/java/net/minecraft/nbt/NBTTagLong.java index 6ebe6233..cc2accf6 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagLong.java +++ b/src/game/java/net/minecraft/nbt/NBTTagLong.java @@ -10,7 +10,7 @@ import java.io.IOException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/nbt/NBTTagShort.java b/src/game/java/net/minecraft/nbt/NBTTagShort.java index 34dd3300..ec531aba 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagShort.java +++ b/src/game/java/net/minecraft/nbt/NBTTagShort.java @@ -10,7 +10,7 @@ import java.io.IOException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/nbt/NBTTagString.java b/src/game/java/net/minecraft/nbt/NBTTagString.java index 5d4fb080..9107d9ad 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagString.java +++ b/src/game/java/net/minecraft/nbt/NBTTagString.java @@ -10,7 +10,7 @@ import java.io.IOException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/nbt/NBTUtil.java b/src/game/java/net/minecraft/nbt/NBTUtil.java index ba1d1d77..b513935d 100755 --- a/src/game/java/net/minecraft/nbt/NBTUtil.java +++ b/src/game/java/net/minecraft/nbt/NBTUtil.java @@ -15,7 +15,7 @@ import net.minecraft.util.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/EnumConnectionState.java b/src/game/java/net/minecraft/network/EnumConnectionState.java index 1c0b4a17..23b651f7 100755 --- a/src/game/java/net/minecraft/network/EnumConnectionState.java +++ b/src/game/java/net/minecraft/network/EnumConnectionState.java @@ -117,7 +117,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/EnumPacketDirection.java b/src/game/java/net/minecraft/network/EnumPacketDirection.java index a31334f7..3863cf23 100755 --- a/src/game/java/net/minecraft/network/EnumPacketDirection.java +++ b/src/game/java/net/minecraft/network/EnumPacketDirection.java @@ -6,7 +6,7 @@ package net.minecraft.network; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/INetHandler.java b/src/game/java/net/minecraft/network/INetHandler.java index 604541c4..fa393751 100755 --- a/src/game/java/net/minecraft/network/INetHandler.java +++ b/src/game/java/net/minecraft/network/INetHandler.java @@ -8,7 +8,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/NetHandlerPlayServer.java b/src/game/java/net/minecraft/network/NetHandlerPlayServer.java index c1a3a064..b1005872 100755 --- a/src/game/java/net/minecraft/network/NetHandlerPlayServer.java +++ b/src/game/java/net/minecraft/network/NetHandlerPlayServer.java @@ -1,5 +1,7 @@ package net.minecraft.network; +import com.carrotsearch.hppc.IntShortHashMap; +import com.carrotsearch.hppc.IntShortMap; import com.google.common.collect.Lists; import com.google.common.primitives.Doubles; import com.google.common.primitives.Floats; @@ -88,7 +90,6 @@ import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.EnumFacing; import net.minecraft.util.IChatComponent; import net.minecraft.util.ITickable; -import net.minecraft.util.IntHashMap; import net.minecraft.util.ReportedException; import net.minecraft.world.WorldServer; import net.lax1dude.eaglercraft.v1_8.sp.server.socket.IntegratedServerPlayerNetworkManager; @@ -105,7 +106,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -134,7 +135,7 @@ public class NetHandlerPlayServer implements INetHandlerPlayServer, ITickable { private long lastSentPingPacket; private int chatSpamThresholdCount; private int itemDropThreshold; - private IntHashMap field_147372_n = new IntHashMap(); + private IntShortMap field_147372_n = new IntShortHashMap(); private double lastPosX; private double lastPosY; private double lastPosZ; @@ -928,8 +929,8 @@ public class NetHandlerPlayServer implements INetHandlerPlayServer, ITickable { this.playerEntity.updateHeldItem(); this.playerEntity.isChangingQuantityOnly = false; } else { - this.field_147372_n.addKey(this.playerEntity.openContainer.windowId, - Short.valueOf(c0epacketclickwindow.getActionNumber())); + this.field_147372_n.put(this.playerEntity.openContainer.windowId, + c0epacketclickwindow.getActionNumber()); this.playerEntity.playerNetServerHandler.sendPacket(new S32PacketConfirmTransaction( c0epacketclickwindow.getWindowId(), c0epacketclickwindow.getActionNumber(), false)); this.playerEntity.openContainer.setCanCraft(this.playerEntity, false); @@ -1019,14 +1020,14 @@ public class NetHandlerPlayServer implements INetHandlerPlayServer, ITickable { * player's ability to manipulate the container contents */ public void processConfirmTransaction(C0FPacketConfirmTransaction c0fpacketconfirmtransaction) { - Short oshort = (Short) this.field_147372_n.lookup(this.playerEntity.openContainer.windowId); - if (oshort != null && c0fpacketconfirmtransaction.getUid() == oshort.shortValue() - && this.playerEntity.openContainer.windowId == c0fpacketconfirmtransaction.getWindowId() + int windowId = this.playerEntity.openContainer.windowId; + if (this.field_147372_n.containsKey(windowId) + && c0fpacketconfirmtransaction.getUid() == this.field_147372_n.get(windowId) + && windowId == c0fpacketconfirmtransaction.getWindowId() && !this.playerEntity.openContainer.getCanCraft(this.playerEntity) && !this.playerEntity.isSpectator()) { this.playerEntity.openContainer.setCanCraft(this.playerEntity, true); } - } public void processUpdateSign(C12PacketUpdateSign c12packetupdatesign) { diff --git a/src/game/java/net/minecraft/network/Packet.java b/src/game/java/net/minecraft/network/Packet.java index 13bcf6ea..131cd2c6 100755 --- a/src/game/java/net/minecraft/network/Packet.java +++ b/src/game/java/net/minecraft/network/Packet.java @@ -8,7 +8,7 @@ import java.io.IOException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/PacketBuffer.java b/src/game/java/net/minecraft/network/PacketBuffer.java index 2a151308..a7d35846 100755 --- a/src/game/java/net/minecraft/network/PacketBuffer.java +++ b/src/game/java/net/minecraft/network/PacketBuffer.java @@ -30,7 +30,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/ServerStatusResponse.java b/src/game/java/net/minecraft/network/ServerStatusResponse.java index 38f2ad12..39b19781 100755 --- a/src/game/java/net/minecraft/network/ServerStatusResponse.java +++ b/src/game/java/net/minecraft/network/ServerStatusResponse.java @@ -16,7 +16,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/handshake/INetHandlerHandshakeServer.java b/src/game/java/net/minecraft/network/handshake/INetHandlerHandshakeServer.java index 0bde65df..59593efd 100755 --- a/src/game/java/net/minecraft/network/handshake/INetHandlerHandshakeServer.java +++ b/src/game/java/net/minecraft/network/handshake/INetHandlerHandshakeServer.java @@ -9,7 +9,7 @@ import net.minecraft.network.handshake.client.C00Handshake; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/handshake/client/C00Handshake.java b/src/game/java/net/minecraft/network/handshake/client/C00Handshake.java index 8d430b01..7b443998 100755 --- a/src/game/java/net/minecraft/network/handshake/client/C00Handshake.java +++ b/src/game/java/net/minecraft/network/handshake/client/C00Handshake.java @@ -13,7 +13,7 @@ import net.minecraft.network.handshake.INetHandlerHandshakeServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/login/INetHandlerLoginClient.java b/src/game/java/net/minecraft/network/login/INetHandlerLoginClient.java index ae351a07..ce48fe1f 100755 --- a/src/game/java/net/minecraft/network/login/INetHandlerLoginClient.java +++ b/src/game/java/net/minecraft/network/login/INetHandlerLoginClient.java @@ -12,7 +12,7 @@ import net.minecraft.network.login.server.S03PacketEnableCompression; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/login/INetHandlerLoginServer.java b/src/game/java/net/minecraft/network/login/INetHandlerLoginServer.java index d0662d03..229642e3 100755 --- a/src/game/java/net/minecraft/network/login/INetHandlerLoginServer.java +++ b/src/game/java/net/minecraft/network/login/INetHandlerLoginServer.java @@ -10,7 +10,7 @@ import net.minecraft.network.login.client.C01PacketEncryptionResponse; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/login/client/C00PacketLoginStart.java b/src/game/java/net/minecraft/network/login/client/C00PacketLoginStart.java index c2674ba2..08ea7ee7 100755 --- a/src/game/java/net/minecraft/network/login/client/C00PacketLoginStart.java +++ b/src/game/java/net/minecraft/network/login/client/C00PacketLoginStart.java @@ -13,7 +13,7 @@ import net.minecraft.network.login.INetHandlerLoginServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/login/client/C01PacketEncryptionResponse.java b/src/game/java/net/minecraft/network/login/client/C01PacketEncryptionResponse.java index fb8603e9..a6136398 100755 --- a/src/game/java/net/minecraft/network/login/client/C01PacketEncryptionResponse.java +++ b/src/game/java/net/minecraft/network/login/client/C01PacketEncryptionResponse.java @@ -12,7 +12,7 @@ import net.minecraft.network.login.INetHandlerLoginServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/login/server/S00PacketDisconnect.java b/src/game/java/net/minecraft/network/login/server/S00PacketDisconnect.java index 3a0b6077..be4d1e43 100755 --- a/src/game/java/net/minecraft/network/login/server/S00PacketDisconnect.java +++ b/src/game/java/net/minecraft/network/login/server/S00PacketDisconnect.java @@ -13,7 +13,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/login/server/S01PacketEncryptionRequest.java b/src/game/java/net/minecraft/network/login/server/S01PacketEncryptionRequest.java index b54a96a1..3db2bacb 100755 --- a/src/game/java/net/minecraft/network/login/server/S01PacketEncryptionRequest.java +++ b/src/game/java/net/minecraft/network/login/server/S01PacketEncryptionRequest.java @@ -12,7 +12,7 @@ import net.minecraft.network.login.INetHandlerLoginClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/login/server/S02PacketLoginSuccess.java b/src/game/java/net/minecraft/network/login/server/S02PacketLoginSuccess.java index da521262..83189444 100755 --- a/src/game/java/net/minecraft/network/login/server/S02PacketLoginSuccess.java +++ b/src/game/java/net/minecraft/network/login/server/S02PacketLoginSuccess.java @@ -14,7 +14,7 @@ import net.minecraft.network.login.INetHandlerLoginClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/login/server/S03PacketEnableCompression.java b/src/game/java/net/minecraft/network/login/server/S03PacketEnableCompression.java index 8326206a..737ae33b 100755 --- a/src/game/java/net/minecraft/network/login/server/S03PacketEnableCompression.java +++ b/src/game/java/net/minecraft/network/login/server/S03PacketEnableCompression.java @@ -12,7 +12,7 @@ import net.minecraft.network.login.INetHandlerLoginClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/INetHandlerPlayClient.java b/src/game/java/net/minecraft/network/play/INetHandlerPlayClient.java index 9e9a19d9..ea688c47 100755 --- a/src/game/java/net/minecraft/network/play/INetHandlerPlayClient.java +++ b/src/game/java/net/minecraft/network/play/INetHandlerPlayClient.java @@ -79,7 +79,7 @@ import net.minecraft.network.play.server.S49PacketUpdateEntityNBT; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/INetHandlerPlayServer.java b/src/game/java/net/minecraft/network/play/INetHandlerPlayServer.java index d6a4b5bc..2ed788b6 100755 --- a/src/game/java/net/minecraft/network/play/INetHandlerPlayServer.java +++ b/src/game/java/net/minecraft/network/play/INetHandlerPlayServer.java @@ -31,7 +31,7 @@ import net.minecraft.network.play.client.C19PacketResourcePackStatus; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C00PacketKeepAlive.java b/src/game/java/net/minecraft/network/play/client/C00PacketKeepAlive.java index 92d6baae..ea7ef33c 100755 --- a/src/game/java/net/minecraft/network/play/client/C00PacketKeepAlive.java +++ b/src/game/java/net/minecraft/network/play/client/C00PacketKeepAlive.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C01PacketChatMessage.java b/src/game/java/net/minecraft/network/play/client/C01PacketChatMessage.java index 99f29fda..8fd8c4ec 100755 --- a/src/game/java/net/minecraft/network/play/client/C01PacketChatMessage.java +++ b/src/game/java/net/minecraft/network/play/client/C01PacketChatMessage.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C02PacketUseEntity.java b/src/game/java/net/minecraft/network/play/client/C02PacketUseEntity.java index 815ed7cc..ce046bc6 100755 --- a/src/game/java/net/minecraft/network/play/client/C02PacketUseEntity.java +++ b/src/game/java/net/minecraft/network/play/client/C02PacketUseEntity.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C03PacketPlayer.java b/src/game/java/net/minecraft/network/play/client/C03PacketPlayer.java index 0b5cbf7c..fd010126 100755 --- a/src/game/java/net/minecraft/network/play/client/C03PacketPlayer.java +++ b/src/game/java/net/minecraft/network/play/client/C03PacketPlayer.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C07PacketPlayerDigging.java b/src/game/java/net/minecraft/network/play/client/C07PacketPlayerDigging.java index 268f3407..d1cd7309 100755 --- a/src/game/java/net/minecraft/network/play/client/C07PacketPlayerDigging.java +++ b/src/game/java/net/minecraft/network/play/client/C07PacketPlayerDigging.java @@ -14,7 +14,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C08PacketPlayerBlockPlacement.java b/src/game/java/net/minecraft/network/play/client/C08PacketPlayerBlockPlacement.java index 178c71c2..410ca004 100755 --- a/src/game/java/net/minecraft/network/play/client/C08PacketPlayerBlockPlacement.java +++ b/src/game/java/net/minecraft/network/play/client/C08PacketPlayerBlockPlacement.java @@ -14,7 +14,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C09PacketHeldItemChange.java b/src/game/java/net/minecraft/network/play/client/C09PacketHeldItemChange.java index dce72c76..efbf45ef 100755 --- a/src/game/java/net/minecraft/network/play/client/C09PacketHeldItemChange.java +++ b/src/game/java/net/minecraft/network/play/client/C09PacketHeldItemChange.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C0APacketAnimation.java b/src/game/java/net/minecraft/network/play/client/C0APacketAnimation.java index 88ff6ea9..c5a08581 100755 --- a/src/game/java/net/minecraft/network/play/client/C0APacketAnimation.java +++ b/src/game/java/net/minecraft/network/play/client/C0APacketAnimation.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C0BPacketEntityAction.java b/src/game/java/net/minecraft/network/play/client/C0BPacketEntityAction.java index e7cce2a0..db46b39f 100755 --- a/src/game/java/net/minecraft/network/play/client/C0BPacketEntityAction.java +++ b/src/game/java/net/minecraft/network/play/client/C0BPacketEntityAction.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C0CPacketInput.java b/src/game/java/net/minecraft/network/play/client/C0CPacketInput.java index a9af9a67..3a046db8 100755 --- a/src/game/java/net/minecraft/network/play/client/C0CPacketInput.java +++ b/src/game/java/net/minecraft/network/play/client/C0CPacketInput.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C0DPacketCloseWindow.java b/src/game/java/net/minecraft/network/play/client/C0DPacketCloseWindow.java index 2ebfeef7..55fb554e 100755 --- a/src/game/java/net/minecraft/network/play/client/C0DPacketCloseWindow.java +++ b/src/game/java/net/minecraft/network/play/client/C0DPacketCloseWindow.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C0EPacketClickWindow.java b/src/game/java/net/minecraft/network/play/client/C0EPacketClickWindow.java index df1a9019..365299f7 100755 --- a/src/game/java/net/minecraft/network/play/client/C0EPacketClickWindow.java +++ b/src/game/java/net/minecraft/network/play/client/C0EPacketClickWindow.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C0FPacketConfirmTransaction.java b/src/game/java/net/minecraft/network/play/client/C0FPacketConfirmTransaction.java index 33515cf1..64ab6a7b 100755 --- a/src/game/java/net/minecraft/network/play/client/C0FPacketConfirmTransaction.java +++ b/src/game/java/net/minecraft/network/play/client/C0FPacketConfirmTransaction.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C10PacketCreativeInventoryAction.java b/src/game/java/net/minecraft/network/play/client/C10PacketCreativeInventoryAction.java index a33d3b64..7642226a 100755 --- a/src/game/java/net/minecraft/network/play/client/C10PacketCreativeInventoryAction.java +++ b/src/game/java/net/minecraft/network/play/client/C10PacketCreativeInventoryAction.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C11PacketEnchantItem.java b/src/game/java/net/minecraft/network/play/client/C11PacketEnchantItem.java index f2ae5f3f..69a282de 100755 --- a/src/game/java/net/minecraft/network/play/client/C11PacketEnchantItem.java +++ b/src/game/java/net/minecraft/network/play/client/C11PacketEnchantItem.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C12PacketUpdateSign.java b/src/game/java/net/minecraft/network/play/client/C12PacketUpdateSign.java index 1c984cc6..8563b373 100755 --- a/src/game/java/net/minecraft/network/play/client/C12PacketUpdateSign.java +++ b/src/game/java/net/minecraft/network/play/client/C12PacketUpdateSign.java @@ -14,7 +14,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C13PacketPlayerAbilities.java b/src/game/java/net/minecraft/network/play/client/C13PacketPlayerAbilities.java index 0e249763..557492f9 100755 --- a/src/game/java/net/minecraft/network/play/client/C13PacketPlayerAbilities.java +++ b/src/game/java/net/minecraft/network/play/client/C13PacketPlayerAbilities.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C14PacketTabComplete.java b/src/game/java/net/minecraft/network/play/client/C14PacketTabComplete.java index 90712ee0..0605e5b7 100755 --- a/src/game/java/net/minecraft/network/play/client/C14PacketTabComplete.java +++ b/src/game/java/net/minecraft/network/play/client/C14PacketTabComplete.java @@ -15,7 +15,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C15PacketClientSettings.java b/src/game/java/net/minecraft/network/play/client/C15PacketClientSettings.java index 933e6f77..86890d53 100755 --- a/src/game/java/net/minecraft/network/play/client/C15PacketClientSettings.java +++ b/src/game/java/net/minecraft/network/play/client/C15PacketClientSettings.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C16PacketClientStatus.java b/src/game/java/net/minecraft/network/play/client/C16PacketClientStatus.java index 5cc4658a..81fdd1ed 100755 --- a/src/game/java/net/minecraft/network/play/client/C16PacketClientStatus.java +++ b/src/game/java/net/minecraft/network/play/client/C16PacketClientStatus.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C17PacketCustomPayload.java b/src/game/java/net/minecraft/network/play/client/C17PacketCustomPayload.java index 20589d05..18852ad1 100755 --- a/src/game/java/net/minecraft/network/play/client/C17PacketCustomPayload.java +++ b/src/game/java/net/minecraft/network/play/client/C17PacketCustomPayload.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C18PacketSpectate.java b/src/game/java/net/minecraft/network/play/client/C18PacketSpectate.java index c3b95a42..6c0410ed 100755 --- a/src/game/java/net/minecraft/network/play/client/C18PacketSpectate.java +++ b/src/game/java/net/minecraft/network/play/client/C18PacketSpectate.java @@ -14,7 +14,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/client/C19PacketResourcePackStatus.java b/src/game/java/net/minecraft/network/play/client/C19PacketResourcePackStatus.java index d0103f94..a18a134c 100755 --- a/src/game/java/net/minecraft/network/play/client/C19PacketResourcePackStatus.java +++ b/src/game/java/net/minecraft/network/play/client/C19PacketResourcePackStatus.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S00PacketKeepAlive.java b/src/game/java/net/minecraft/network/play/server/S00PacketKeepAlive.java index 1870cdba..a3ed1088 100755 --- a/src/game/java/net/minecraft/network/play/server/S00PacketKeepAlive.java +++ b/src/game/java/net/minecraft/network/play/server/S00PacketKeepAlive.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S01PacketJoinGame.java b/src/game/java/net/minecraft/network/play/server/S01PacketJoinGame.java index 1b366b09..65dd6459 100755 --- a/src/game/java/net/minecraft/network/play/server/S01PacketJoinGame.java +++ b/src/game/java/net/minecraft/network/play/server/S01PacketJoinGame.java @@ -15,7 +15,7 @@ import net.minecraft.world.WorldType; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S02PacketChat.java b/src/game/java/net/minecraft/network/play/server/S02PacketChat.java index 262eef6f..8aba9dde 100755 --- a/src/game/java/net/minecraft/network/play/server/S02PacketChat.java +++ b/src/game/java/net/minecraft/network/play/server/S02PacketChat.java @@ -13,7 +13,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S03PacketTimeUpdate.java b/src/game/java/net/minecraft/network/play/server/S03PacketTimeUpdate.java index 80dd7fc5..4d2ea84a 100755 --- a/src/game/java/net/minecraft/network/play/server/S03PacketTimeUpdate.java +++ b/src/game/java/net/minecraft/network/play/server/S03PacketTimeUpdate.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S04PacketEntityEquipment.java b/src/game/java/net/minecraft/network/play/server/S04PacketEntityEquipment.java index 7fb92d65..d34df912 100755 --- a/src/game/java/net/minecraft/network/play/server/S04PacketEntityEquipment.java +++ b/src/game/java/net/minecraft/network/play/server/S04PacketEntityEquipment.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S05PacketSpawnPosition.java b/src/game/java/net/minecraft/network/play/server/S05PacketSpawnPosition.java index 6315718e..cf70ffb4 100755 --- a/src/game/java/net/minecraft/network/play/server/S05PacketSpawnPosition.java +++ b/src/game/java/net/minecraft/network/play/server/S05PacketSpawnPosition.java @@ -13,7 +13,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S06PacketUpdateHealth.java b/src/game/java/net/minecraft/network/play/server/S06PacketUpdateHealth.java index 3818bc3e..3eaf465f 100755 --- a/src/game/java/net/minecraft/network/play/server/S06PacketUpdateHealth.java +++ b/src/game/java/net/minecraft/network/play/server/S06PacketUpdateHealth.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S07PacketRespawn.java b/src/game/java/net/minecraft/network/play/server/S07PacketRespawn.java index 3fb5f615..48097b47 100755 --- a/src/game/java/net/minecraft/network/play/server/S07PacketRespawn.java +++ b/src/game/java/net/minecraft/network/play/server/S07PacketRespawn.java @@ -15,7 +15,7 @@ import net.minecraft.world.WorldType; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S08PacketPlayerPosLook.java b/src/game/java/net/minecraft/network/play/server/S08PacketPlayerPosLook.java index 7f8701c8..dbc4c632 100755 --- a/src/game/java/net/minecraft/network/play/server/S08PacketPlayerPosLook.java +++ b/src/game/java/net/minecraft/network/play/server/S08PacketPlayerPosLook.java @@ -14,7 +14,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S09PacketHeldItemChange.java b/src/game/java/net/minecraft/network/play/server/S09PacketHeldItemChange.java index 560e3da0..e36801d0 100755 --- a/src/game/java/net/minecraft/network/play/server/S09PacketHeldItemChange.java +++ b/src/game/java/net/minecraft/network/play/server/S09PacketHeldItemChange.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S0APacketUseBed.java b/src/game/java/net/minecraft/network/play/server/S0APacketUseBed.java index 757ce11b..b1f0727d 100755 --- a/src/game/java/net/minecraft/network/play/server/S0APacketUseBed.java +++ b/src/game/java/net/minecraft/network/play/server/S0APacketUseBed.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S0BPacketAnimation.java b/src/game/java/net/minecraft/network/play/server/S0BPacketAnimation.java index 426b15ed..b4b993a4 100755 --- a/src/game/java/net/minecraft/network/play/server/S0BPacketAnimation.java +++ b/src/game/java/net/minecraft/network/play/server/S0BPacketAnimation.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S0CPacketSpawnPlayer.java b/src/game/java/net/minecraft/network/play/server/S0CPacketSpawnPlayer.java index 1fb5008c..9b7b6c5d 100755 --- a/src/game/java/net/minecraft/network/play/server/S0CPacketSpawnPlayer.java +++ b/src/game/java/net/minecraft/network/play/server/S0CPacketSpawnPlayer.java @@ -19,7 +19,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S0DPacketCollectItem.java b/src/game/java/net/minecraft/network/play/server/S0DPacketCollectItem.java index 4b463258..b31a1f7b 100755 --- a/src/game/java/net/minecraft/network/play/server/S0DPacketCollectItem.java +++ b/src/game/java/net/minecraft/network/play/server/S0DPacketCollectItem.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S0EPacketSpawnObject.java b/src/game/java/net/minecraft/network/play/server/S0EPacketSpawnObject.java index 35d82274..a278cd76 100755 --- a/src/game/java/net/minecraft/network/play/server/S0EPacketSpawnObject.java +++ b/src/game/java/net/minecraft/network/play/server/S0EPacketSpawnObject.java @@ -14,7 +14,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S0FPacketSpawnMob.java b/src/game/java/net/minecraft/network/play/server/S0FPacketSpawnMob.java index 73f3fee5..64d41fc1 100755 --- a/src/game/java/net/minecraft/network/play/server/S0FPacketSpawnMob.java +++ b/src/game/java/net/minecraft/network/play/server/S0FPacketSpawnMob.java @@ -17,7 +17,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S10PacketSpawnPainting.java b/src/game/java/net/minecraft/network/play/server/S10PacketSpawnPainting.java index 430ccec0..3f51f69b 100755 --- a/src/game/java/net/minecraft/network/play/server/S10PacketSpawnPainting.java +++ b/src/game/java/net/minecraft/network/play/server/S10PacketSpawnPainting.java @@ -15,7 +15,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S11PacketSpawnExperienceOrb.java b/src/game/java/net/minecraft/network/play/server/S11PacketSpawnExperienceOrb.java index e22b387b..f41d2170 100755 --- a/src/game/java/net/minecraft/network/play/server/S11PacketSpawnExperienceOrb.java +++ b/src/game/java/net/minecraft/network/play/server/S11PacketSpawnExperienceOrb.java @@ -14,7 +14,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S12PacketEntityVelocity.java b/src/game/java/net/minecraft/network/play/server/S12PacketEntityVelocity.java index c3fbc630..ee56af6d 100755 --- a/src/game/java/net/minecraft/network/play/server/S12PacketEntityVelocity.java +++ b/src/game/java/net/minecraft/network/play/server/S12PacketEntityVelocity.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S13PacketDestroyEntities.java b/src/game/java/net/minecraft/network/play/server/S13PacketDestroyEntities.java index e038cb99..0ae5e329 100755 --- a/src/game/java/net/minecraft/network/play/server/S13PacketDestroyEntities.java +++ b/src/game/java/net/minecraft/network/play/server/S13PacketDestroyEntities.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S14PacketEntity.java b/src/game/java/net/minecraft/network/play/server/S14PacketEntity.java index 9ed2dcb3..077c3235 100755 --- a/src/game/java/net/minecraft/network/play/server/S14PacketEntity.java +++ b/src/game/java/net/minecraft/network/play/server/S14PacketEntity.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S18PacketEntityTeleport.java b/src/game/java/net/minecraft/network/play/server/S18PacketEntityTeleport.java index e873c91e..00888838 100755 --- a/src/game/java/net/minecraft/network/play/server/S18PacketEntityTeleport.java +++ b/src/game/java/net/minecraft/network/play/server/S18PacketEntityTeleport.java @@ -14,7 +14,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S19PacketEntityHeadLook.java b/src/game/java/net/minecraft/network/play/server/S19PacketEntityHeadLook.java index d1adefc5..94e2ad61 100755 --- a/src/game/java/net/minecraft/network/play/server/S19PacketEntityHeadLook.java +++ b/src/game/java/net/minecraft/network/play/server/S19PacketEntityHeadLook.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S19PacketEntityStatus.java b/src/game/java/net/minecraft/network/play/server/S19PacketEntityStatus.java index 6dd331f6..e598059c 100755 --- a/src/game/java/net/minecraft/network/play/server/S19PacketEntityStatus.java +++ b/src/game/java/net/minecraft/network/play/server/S19PacketEntityStatus.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S1BPacketEntityAttach.java b/src/game/java/net/minecraft/network/play/server/S1BPacketEntityAttach.java index c2e8636c..af1c31f7 100755 --- a/src/game/java/net/minecraft/network/play/server/S1BPacketEntityAttach.java +++ b/src/game/java/net/minecraft/network/play/server/S1BPacketEntityAttach.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S1CPacketEntityMetadata.java b/src/game/java/net/minecraft/network/play/server/S1CPacketEntityMetadata.java index 79984f18..34b5ce86 100755 --- a/src/game/java/net/minecraft/network/play/server/S1CPacketEntityMetadata.java +++ b/src/game/java/net/minecraft/network/play/server/S1CPacketEntityMetadata.java @@ -14,7 +14,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S1DPacketEntityEffect.java b/src/game/java/net/minecraft/network/play/server/S1DPacketEntityEffect.java index fd3f9e07..d1a33b62 100755 --- a/src/game/java/net/minecraft/network/play/server/S1DPacketEntityEffect.java +++ b/src/game/java/net/minecraft/network/play/server/S1DPacketEntityEffect.java @@ -13,7 +13,7 @@ import net.minecraft.potion.PotionEffect; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S1EPacketRemoveEntityEffect.java b/src/game/java/net/minecraft/network/play/server/S1EPacketRemoveEntityEffect.java index e3d5e989..3f769314 100755 --- a/src/game/java/net/minecraft/network/play/server/S1EPacketRemoveEntityEffect.java +++ b/src/game/java/net/minecraft/network/play/server/S1EPacketRemoveEntityEffect.java @@ -13,7 +13,7 @@ import net.minecraft.potion.PotionEffect; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S1FPacketSetExperience.java b/src/game/java/net/minecraft/network/play/server/S1FPacketSetExperience.java index e398627e..aae8c968 100755 --- a/src/game/java/net/minecraft/network/play/server/S1FPacketSetExperience.java +++ b/src/game/java/net/minecraft/network/play/server/S1FPacketSetExperience.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S20PacketEntityProperties.java b/src/game/java/net/minecraft/network/play/server/S20PacketEntityProperties.java index 65e9cf80..efe5df6a 100755 --- a/src/game/java/net/minecraft/network/play/server/S20PacketEntityProperties.java +++ b/src/game/java/net/minecraft/network/play/server/S20PacketEntityProperties.java @@ -20,7 +20,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S21PacketChunkData.java b/src/game/java/net/minecraft/network/play/server/S21PacketChunkData.java index 202ecd34..5b8578ea 100755 --- a/src/game/java/net/minecraft/network/play/server/S21PacketChunkData.java +++ b/src/game/java/net/minecraft/network/play/server/S21PacketChunkData.java @@ -17,7 +17,7 @@ import net.minecraft.world.chunk.storage.ExtendedBlockStorage; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S22PacketMultiBlockChange.java b/src/game/java/net/minecraft/network/play/server/S22PacketMultiBlockChange.java index 85612f06..7ef56493 100755 --- a/src/game/java/net/minecraft/network/play/server/S22PacketMultiBlockChange.java +++ b/src/game/java/net/minecraft/network/play/server/S22PacketMultiBlockChange.java @@ -17,7 +17,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S23PacketBlockChange.java b/src/game/java/net/minecraft/network/play/server/S23PacketBlockChange.java index ee2e4346..181a53d2 100755 --- a/src/game/java/net/minecraft/network/play/server/S23PacketBlockChange.java +++ b/src/game/java/net/minecraft/network/play/server/S23PacketBlockChange.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S24PacketBlockAction.java b/src/game/java/net/minecraft/network/play/server/S24PacketBlockAction.java index 5effada3..cdfd9d03 100755 --- a/src/game/java/net/minecraft/network/play/server/S24PacketBlockAction.java +++ b/src/game/java/net/minecraft/network/play/server/S24PacketBlockAction.java @@ -14,7 +14,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S25PacketBlockBreakAnim.java b/src/game/java/net/minecraft/network/play/server/S25PacketBlockBreakAnim.java index c436f516..a443595b 100755 --- a/src/game/java/net/minecraft/network/play/server/S25PacketBlockBreakAnim.java +++ b/src/game/java/net/minecraft/network/play/server/S25PacketBlockBreakAnim.java @@ -13,7 +13,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S26PacketMapChunkBulk.java b/src/game/java/net/minecraft/network/play/server/S26PacketMapChunkBulk.java index 3da9332a..36b9eed6 100755 --- a/src/game/java/net/minecraft/network/play/server/S26PacketMapChunkBulk.java +++ b/src/game/java/net/minecraft/network/play/server/S26PacketMapChunkBulk.java @@ -14,7 +14,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S27PacketExplosion.java b/src/game/java/net/minecraft/network/play/server/S27PacketExplosion.java index 5957af7c..34b17201 100755 --- a/src/game/java/net/minecraft/network/play/server/S27PacketExplosion.java +++ b/src/game/java/net/minecraft/network/play/server/S27PacketExplosion.java @@ -17,7 +17,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S28PacketEffect.java b/src/game/java/net/minecraft/network/play/server/S28PacketEffect.java index b22379bd..f8e02f5c 100755 --- a/src/game/java/net/minecraft/network/play/server/S28PacketEffect.java +++ b/src/game/java/net/minecraft/network/play/server/S28PacketEffect.java @@ -13,7 +13,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S29PacketSoundEffect.java b/src/game/java/net/minecraft/network/play/server/S29PacketSoundEffect.java index 563b8235..7caa9281 100755 --- a/src/game/java/net/minecraft/network/play/server/S29PacketSoundEffect.java +++ b/src/game/java/net/minecraft/network/play/server/S29PacketSoundEffect.java @@ -15,7 +15,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S2APacketParticles.java b/src/game/java/net/minecraft/network/play/server/S2APacketParticles.java index d6e3ab44..c32af4ea 100755 --- a/src/game/java/net/minecraft/network/play/server/S2APacketParticles.java +++ b/src/game/java/net/minecraft/network/play/server/S2APacketParticles.java @@ -13,7 +13,7 @@ import net.minecraft.util.EnumParticleTypes; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S2BPacketChangeGameState.java b/src/game/java/net/minecraft/network/play/server/S2BPacketChangeGameState.java index 1a0235aa..869664a2 100755 --- a/src/game/java/net/minecraft/network/play/server/S2BPacketChangeGameState.java +++ b/src/game/java/net/minecraft/network/play/server/S2BPacketChangeGameState.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S2CPacketSpawnGlobalEntity.java b/src/game/java/net/minecraft/network/play/server/S2CPacketSpawnGlobalEntity.java index e1838b4a..a2b10fe1 100755 --- a/src/game/java/net/minecraft/network/play/server/S2CPacketSpawnGlobalEntity.java +++ b/src/game/java/net/minecraft/network/play/server/S2CPacketSpawnGlobalEntity.java @@ -15,7 +15,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S2DPacketOpenWindow.java b/src/game/java/net/minecraft/network/play/server/S2DPacketOpenWindow.java index df7f4584..25f15d8a 100755 --- a/src/game/java/net/minecraft/network/play/server/S2DPacketOpenWindow.java +++ b/src/game/java/net/minecraft/network/play/server/S2DPacketOpenWindow.java @@ -13,7 +13,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S2EPacketCloseWindow.java b/src/game/java/net/minecraft/network/play/server/S2EPacketCloseWindow.java index 4a584608..d8a97602 100755 --- a/src/game/java/net/minecraft/network/play/server/S2EPacketCloseWindow.java +++ b/src/game/java/net/minecraft/network/play/server/S2EPacketCloseWindow.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S2FPacketSetSlot.java b/src/game/java/net/minecraft/network/play/server/S2FPacketSetSlot.java index 65917702..35fa5bd2 100755 --- a/src/game/java/net/minecraft/network/play/server/S2FPacketSetSlot.java +++ b/src/game/java/net/minecraft/network/play/server/S2FPacketSetSlot.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S30PacketWindowItems.java b/src/game/java/net/minecraft/network/play/server/S30PacketWindowItems.java index a75fe45d..b60ce29d 100755 --- a/src/game/java/net/minecraft/network/play/server/S30PacketWindowItems.java +++ b/src/game/java/net/minecraft/network/play/server/S30PacketWindowItems.java @@ -14,7 +14,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S31PacketWindowProperty.java b/src/game/java/net/minecraft/network/play/server/S31PacketWindowProperty.java index fb7a14ee..0c06ca26 100755 --- a/src/game/java/net/minecraft/network/play/server/S31PacketWindowProperty.java +++ b/src/game/java/net/minecraft/network/play/server/S31PacketWindowProperty.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S32PacketConfirmTransaction.java b/src/game/java/net/minecraft/network/play/server/S32PacketConfirmTransaction.java index 230538b3..f340d3d4 100755 --- a/src/game/java/net/minecraft/network/play/server/S32PacketConfirmTransaction.java +++ b/src/game/java/net/minecraft/network/play/server/S32PacketConfirmTransaction.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S33PacketUpdateSign.java b/src/game/java/net/minecraft/network/play/server/S33PacketUpdateSign.java index 79678ce8..80e3a79d 100755 --- a/src/game/java/net/minecraft/network/play/server/S33PacketUpdateSign.java +++ b/src/game/java/net/minecraft/network/play/server/S33PacketUpdateSign.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S34PacketMaps.java b/src/game/java/net/minecraft/network/play/server/S34PacketMaps.java index bbdfb8f0..a60f14d2 100755 --- a/src/game/java/net/minecraft/network/play/server/S34PacketMaps.java +++ b/src/game/java/net/minecraft/network/play/server/S34PacketMaps.java @@ -15,7 +15,7 @@ import net.minecraft.world.storage.MapData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S35PacketUpdateTileEntity.java b/src/game/java/net/minecraft/network/play/server/S35PacketUpdateTileEntity.java index db1ab324..bfda1323 100755 --- a/src/game/java/net/minecraft/network/play/server/S35PacketUpdateTileEntity.java +++ b/src/game/java/net/minecraft/network/play/server/S35PacketUpdateTileEntity.java @@ -14,7 +14,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S36PacketSignEditorOpen.java b/src/game/java/net/minecraft/network/play/server/S36PacketSignEditorOpen.java index 8511cd0c..7b45e5b0 100755 --- a/src/game/java/net/minecraft/network/play/server/S36PacketSignEditorOpen.java +++ b/src/game/java/net/minecraft/network/play/server/S36PacketSignEditorOpen.java @@ -13,7 +13,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S37PacketStatistics.java b/src/game/java/net/minecraft/network/play/server/S37PacketStatistics.java index cc0512a4..ca2bfe06 100755 --- a/src/game/java/net/minecraft/network/play/server/S37PacketStatistics.java +++ b/src/game/java/net/minecraft/network/play/server/S37PacketStatistics.java @@ -1,10 +1,10 @@ package net.minecraft.network.play.server; import java.io.IOException; -import java.util.Map; -import java.util.Map.Entry; -import com.google.common.collect.Maps; +import com.carrotsearch.hppc.ObjectIntHashMap; +import com.carrotsearch.hppc.ObjectIntMap; +import com.carrotsearch.hppc.cursors.ObjectIntCursor; import net.minecraft.network.Packet; import net.minecraft.network.PacketBuffer; @@ -18,7 +18,7 @@ import net.minecraft.stats.StatList; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -33,12 +33,12 @@ import net.minecraft.stats.StatList; * */ public class S37PacketStatistics implements Packet { - private Map field_148976_a; + private ObjectIntMap field_148976_a; public S37PacketStatistics() { } - public S37PacketStatistics(Map parMap) { + public S37PacketStatistics(ObjectIntMap parMap) { this.field_148976_a = parMap; } @@ -54,13 +54,13 @@ public class S37PacketStatistics implements Packet { */ public void readPacketData(PacketBuffer parPacketBuffer) throws IOException { int i = parPacketBuffer.readVarIntFromBuffer(); - this.field_148976_a = Maps.newHashMap(); + this.field_148976_a = new ObjectIntHashMap<>(); for (int j = 0; j < i; ++j) { StatBase statbase = StatList.getOneShotStat(parPacketBuffer.readStringFromBuffer(32767)); int k = parPacketBuffer.readVarIntFromBuffer(); if (statbase != null) { - this.field_148976_a.put(statbase, Integer.valueOf(k)); + this.field_148976_a.put(statbase, k); } } @@ -72,14 +72,14 @@ public class S37PacketStatistics implements Packet { public void writePacketData(PacketBuffer parPacketBuffer) throws IOException { parPacketBuffer.writeVarIntToBuffer(this.field_148976_a.size()); - for (Entry entry : this.field_148976_a.entrySet()) { - parPacketBuffer.writeString(((StatBase) entry.getKey()).statId); - parPacketBuffer.writeVarIntToBuffer(((Integer) entry.getValue()).intValue()); + for (ObjectIntCursor entry : this.field_148976_a) { + parPacketBuffer.writeString(entry.key.statId); + parPacketBuffer.writeVarIntToBuffer(entry.value); } } - public Map func_148974_c() { + public ObjectIntMap func_148974_c() { return this.field_148976_a; } } \ No newline at end of file diff --git a/src/game/java/net/minecraft/network/play/server/S38PacketPlayerListItem.java b/src/game/java/net/minecraft/network/play/server/S38PacketPlayerListItem.java index 64767a3f..33cdcaf2 100755 --- a/src/game/java/net/minecraft/network/play/server/S38PacketPlayerListItem.java +++ b/src/game/java/net/minecraft/network/play/server/S38PacketPlayerListItem.java @@ -19,7 +19,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S39PacketPlayerAbilities.java b/src/game/java/net/minecraft/network/play/server/S39PacketPlayerAbilities.java index 81f63b49..f173d655 100755 --- a/src/game/java/net/minecraft/network/play/server/S39PacketPlayerAbilities.java +++ b/src/game/java/net/minecraft/network/play/server/S39PacketPlayerAbilities.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S3APacketTabComplete.java b/src/game/java/net/minecraft/network/play/server/S3APacketTabComplete.java index ef4ed229..45289bbd 100755 --- a/src/game/java/net/minecraft/network/play/server/S3APacketTabComplete.java +++ b/src/game/java/net/minecraft/network/play/server/S3APacketTabComplete.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S3BPacketScoreboardObjective.java b/src/game/java/net/minecraft/network/play/server/S3BPacketScoreboardObjective.java index c8e2ff10..5036b0e0 100755 --- a/src/game/java/net/minecraft/network/play/server/S3BPacketScoreboardObjective.java +++ b/src/game/java/net/minecraft/network/play/server/S3BPacketScoreboardObjective.java @@ -14,7 +14,7 @@ import net.minecraft.scoreboard.ScoreObjective; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S3CPacketUpdateScore.java b/src/game/java/net/minecraft/network/play/server/S3CPacketUpdateScore.java index fec4cbca..c46081e9 100755 --- a/src/game/java/net/minecraft/network/play/server/S3CPacketUpdateScore.java +++ b/src/game/java/net/minecraft/network/play/server/S3CPacketUpdateScore.java @@ -14,7 +14,7 @@ import net.minecraft.scoreboard.ScoreObjective; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S3DPacketDisplayScoreboard.java b/src/game/java/net/minecraft/network/play/server/S3DPacketDisplayScoreboard.java index 116d4a59..824a4838 100755 --- a/src/game/java/net/minecraft/network/play/server/S3DPacketDisplayScoreboard.java +++ b/src/game/java/net/minecraft/network/play/server/S3DPacketDisplayScoreboard.java @@ -13,7 +13,7 @@ import net.minecraft.scoreboard.ScoreObjective; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S3EPacketTeams.java b/src/game/java/net/minecraft/network/play/server/S3EPacketTeams.java index b4623d4b..05b486e7 100755 --- a/src/game/java/net/minecraft/network/play/server/S3EPacketTeams.java +++ b/src/game/java/net/minecraft/network/play/server/S3EPacketTeams.java @@ -17,7 +17,7 @@ import net.minecraft.scoreboard.Team; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S3FPacketCustomPayload.java b/src/game/java/net/minecraft/network/play/server/S3FPacketCustomPayload.java index 86ce71ac..b29edac3 100755 --- a/src/game/java/net/minecraft/network/play/server/S3FPacketCustomPayload.java +++ b/src/game/java/net/minecraft/network/play/server/S3FPacketCustomPayload.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S40PacketDisconnect.java b/src/game/java/net/minecraft/network/play/server/S40PacketDisconnect.java index d3d7b7b7..428f97ee 100755 --- a/src/game/java/net/minecraft/network/play/server/S40PacketDisconnect.java +++ b/src/game/java/net/minecraft/network/play/server/S40PacketDisconnect.java @@ -13,7 +13,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S41PacketServerDifficulty.java b/src/game/java/net/minecraft/network/play/server/S41PacketServerDifficulty.java index 45dceca3..ea08b508 100755 --- a/src/game/java/net/minecraft/network/play/server/S41PacketServerDifficulty.java +++ b/src/game/java/net/minecraft/network/play/server/S41PacketServerDifficulty.java @@ -13,7 +13,7 @@ import net.minecraft.world.EnumDifficulty; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S42PacketCombatEvent.java b/src/game/java/net/minecraft/network/play/server/S42PacketCombatEvent.java index 9d534fc8..7f9b0b03 100755 --- a/src/game/java/net/minecraft/network/play/server/S42PacketCombatEvent.java +++ b/src/game/java/net/minecraft/network/play/server/S42PacketCombatEvent.java @@ -14,7 +14,7 @@ import net.minecraft.util.CombatTracker; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S43PacketCamera.java b/src/game/java/net/minecraft/network/play/server/S43PacketCamera.java index ce25ffd7..528de395 100755 --- a/src/game/java/net/minecraft/network/play/server/S43PacketCamera.java +++ b/src/game/java/net/minecraft/network/play/server/S43PacketCamera.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S44PacketWorldBorder.java b/src/game/java/net/minecraft/network/play/server/S44PacketWorldBorder.java index bca409d9..97622c78 100755 --- a/src/game/java/net/minecraft/network/play/server/S44PacketWorldBorder.java +++ b/src/game/java/net/minecraft/network/play/server/S44PacketWorldBorder.java @@ -13,7 +13,7 @@ import net.minecraft.world.border.WorldBorder; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S45PacketTitle.java b/src/game/java/net/minecraft/network/play/server/S45PacketTitle.java index aef2749a..57fe6d0a 100755 --- a/src/game/java/net/minecraft/network/play/server/S45PacketTitle.java +++ b/src/game/java/net/minecraft/network/play/server/S45PacketTitle.java @@ -13,7 +13,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S46PacketSetCompressionLevel.java b/src/game/java/net/minecraft/network/play/server/S46PacketSetCompressionLevel.java index 247e978c..27e20f49 100755 --- a/src/game/java/net/minecraft/network/play/server/S46PacketSetCompressionLevel.java +++ b/src/game/java/net/minecraft/network/play/server/S46PacketSetCompressionLevel.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S47PacketPlayerListHeaderFooter.java b/src/game/java/net/minecraft/network/play/server/S47PacketPlayerListHeaderFooter.java index 888c18fd..048f46ff 100755 --- a/src/game/java/net/minecraft/network/play/server/S47PacketPlayerListHeaderFooter.java +++ b/src/game/java/net/minecraft/network/play/server/S47PacketPlayerListHeaderFooter.java @@ -13,7 +13,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S48PacketResourcePackSend.java b/src/game/java/net/minecraft/network/play/server/S48PacketResourcePackSend.java index 56b20fed..59b9f0cd 100755 --- a/src/game/java/net/minecraft/network/play/server/S48PacketResourcePackSend.java +++ b/src/game/java/net/minecraft/network/play/server/S48PacketResourcePackSend.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/network/play/server/S49PacketUpdateEntityNBT.java b/src/game/java/net/minecraft/network/play/server/S49PacketUpdateEntityNBT.java index b8c1b361..3deb3479 100755 --- a/src/game/java/net/minecraft/network/play/server/S49PacketUpdateEntityNBT.java +++ b/src/game/java/net/minecraft/network/play/server/S49PacketUpdateEntityNBT.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/pathfinding/Path.java b/src/game/java/net/minecraft/pathfinding/Path.java index 9d1c49c5..4f8eadff 100755 --- a/src/game/java/net/minecraft/pathfinding/Path.java +++ b/src/game/java/net/minecraft/pathfinding/Path.java @@ -6,7 +6,7 @@ package net.minecraft.pathfinding; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/pathfinding/PathEntity.java b/src/game/java/net/minecraft/pathfinding/PathEntity.java index ea31ba58..8e8e41a2 100755 --- a/src/game/java/net/minecraft/pathfinding/PathEntity.java +++ b/src/game/java/net/minecraft/pathfinding/PathEntity.java @@ -9,7 +9,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/pathfinding/PathFinder.java b/src/game/java/net/minecraft/pathfinding/PathFinder.java index 9e81fb81..5079c720 100755 --- a/src/game/java/net/minecraft/pathfinding/PathFinder.java +++ b/src/game/java/net/minecraft/pathfinding/PathFinder.java @@ -11,7 +11,7 @@ import net.minecraft.world.pathfinder.NodeProcessor; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/pathfinding/PathNavigate.java b/src/game/java/net/minecraft/pathfinding/PathNavigate.java index de3f7eed..359ec826 100755 --- a/src/game/java/net/minecraft/pathfinding/PathNavigate.java +++ b/src/game/java/net/minecraft/pathfinding/PathNavigate.java @@ -5,6 +5,7 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.attributes.IAttributeInstance; +import net.minecraft.server.MinecraftServer; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.BlockPos; import net.minecraft.util.MathHelper; @@ -18,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -40,6 +41,8 @@ public abstract class PathNavigate { private final IAttributeInstance pathSearchRange; private int totalTicks; private int ticksAtLastPos; + private int lastFailure = 0; + private int pathfindFailures = 0; /**+ * Coordinates of the entity's position last time a check was * done (part of monitoring getting 'stuck') @@ -134,8 +137,23 @@ public abstract class PathNavigate { * successful. Args : entity, speed */ public boolean tryMoveToEntityLiving(Entity entityIn, double speedIn) { + int i = -1; + if (this.pathfindFailures > 10 && this.currentPath == null + && (i = (int) (MinecraftServer.getCurrentTimeMillis() / 50l)) < this.lastFailure + 40) { + return false; + } + PathEntity pathentity = this.getPathToEntityLiving(entityIn); - return pathentity != null ? this.setPath(pathentity, speedIn) : false; + + if (pathentity != null && this.setPath(pathentity, speedIn)) { + this.lastFailure = 0; + this.pathfindFailures = 0; + return true; + } else { + this.pathfindFailures++; + this.lastFailure = i == -1 ? (int) (MinecraftServer.getCurrentTimeMillis() / 50l) : i; + return false; + } } /**+ @@ -273,6 +291,8 @@ public abstract class PathNavigate { * sets active PathEntity to null */ public void clearPathEntity() { + this.pathfindFailures = 0; + this.lastFailure = 0; this.currentPath = null; } diff --git a/src/game/java/net/minecraft/pathfinding/PathNavigateClimber.java b/src/game/java/net/minecraft/pathfinding/PathNavigateClimber.java index 8cd3c4b7..26b91f82 100755 --- a/src/game/java/net/minecraft/pathfinding/PathNavigateClimber.java +++ b/src/game/java/net/minecraft/pathfinding/PathNavigateClimber.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/pathfinding/PathNavigateGround.java b/src/game/java/net/minecraft/pathfinding/PathNavigateGround.java index 005c9df7..5e1d8cfc 100755 --- a/src/game/java/net/minecraft/pathfinding/PathNavigateGround.java +++ b/src/game/java/net/minecraft/pathfinding/PathNavigateGround.java @@ -18,7 +18,7 @@ import net.minecraft.world.pathfinder.WalkNodeProcessor; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/pathfinding/PathNavigateSwimmer.java b/src/game/java/net/minecraft/pathfinding/PathNavigateSwimmer.java index f96182fd..cbdf9984 100755 --- a/src/game/java/net/minecraft/pathfinding/PathNavigateSwimmer.java +++ b/src/game/java/net/minecraft/pathfinding/PathNavigateSwimmer.java @@ -12,7 +12,7 @@ import net.minecraft.world.pathfinder.SwimNodeProcessor; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/pathfinding/PathPoint.java b/src/game/java/net/minecraft/pathfinding/PathPoint.java index 9cf4234b..806ad93d 100755 --- a/src/game/java/net/minecraft/pathfinding/PathPoint.java +++ b/src/game/java/net/minecraft/pathfinding/PathPoint.java @@ -8,7 +8,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/potion/Potion.java b/src/game/java/net/minecraft/potion/Potion.java index c94a062e..2857a139 100755 --- a/src/game/java/net/minecraft/potion/Potion.java +++ b/src/game/java/net/minecraft/potion/Potion.java @@ -25,7 +25,7 @@ import net.minecraft.util.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/potion/PotionAbsorption.java b/src/game/java/net/minecraft/potion/PotionAbsorption.java index 787b416f..c6563eb9 100755 --- a/src/game/java/net/minecraft/potion/PotionAbsorption.java +++ b/src/game/java/net/minecraft/potion/PotionAbsorption.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/potion/PotionAttackDamage.java b/src/game/java/net/minecraft/potion/PotionAttackDamage.java index 37f6c30f..e0e24a9d 100755 --- a/src/game/java/net/minecraft/potion/PotionAttackDamage.java +++ b/src/game/java/net/minecraft/potion/PotionAttackDamage.java @@ -9,7 +9,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/potion/PotionEffect.java b/src/game/java/net/minecraft/potion/PotionEffect.java index abba81b4..6b3d0540 100755 --- a/src/game/java/net/minecraft/potion/PotionEffect.java +++ b/src/game/java/net/minecraft/potion/PotionEffect.java @@ -11,7 +11,7 @@ import net.minecraft.nbt.NBTTagCompound; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/potion/PotionHealth.java b/src/game/java/net/minecraft/potion/PotionHealth.java index 86587959..74ede3f6 100755 --- a/src/game/java/net/minecraft/potion/PotionHealth.java +++ b/src/game/java/net/minecraft/potion/PotionHealth.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/potion/PotionHealthBoost.java b/src/game/java/net/minecraft/potion/PotionHealthBoost.java index d477727e..2a60dc80 100755 --- a/src/game/java/net/minecraft/potion/PotionHealthBoost.java +++ b/src/game/java/net/minecraft/potion/PotionHealthBoost.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/potion/PotionHelper.java b/src/game/java/net/minecraft/potion/PotionHelper.java index a49a36fc..7b513a86 100755 --- a/src/game/java/net/minecraft/potion/PotionHelper.java +++ b/src/game/java/net/minecraft/potion/PotionHelper.java @@ -3,12 +3,14 @@ package net.minecraft.potion; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Map; +import com.carrotsearch.hppc.IntIntHashMap; +import com.carrotsearch.hppc.IntIntMap; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; +import com.carrotsearch.hppc.ObjectContainer; +import com.carrotsearch.hppc.cursors.ObjectCursor; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -import net.minecraft.util.IntegerCache; /**+ * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. @@ -16,7 +18,7 @@ import net.minecraft.util.IntegerCache; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -45,9 +47,9 @@ public class PotionHelper { public static final String goldenCarrotEffect = "-0+1+2-3+13&4-4"; public static final String pufferfishEffect = "+0-1+2+3+13&4-4"; public static final String rabbitFootEffect = "+0+1-2+3&4-4+13"; - private static final Map potionRequirements = Maps.newHashMap(); - private static final Map potionAmplifiers = Maps.newHashMap(); - private static final Map DATAVALUE_COLORS = Maps.newHashMap(); + private static final IntObjectMap potionRequirements = new IntObjectHashMap<>(); + private static final IntObjectMap potionAmplifiers = new IntObjectHashMap<>(); + private static final IntIntMap DATAVALUE_COLORS = new IntIntHashMap(); /**+ * An array of possible potion prefix names, as translation IDs. */ @@ -133,6 +135,45 @@ public class PotionHelper { } } + /**+ + * Given a {@link Collection}<{@link PotionEffect}> will return + * an Integer color. + */ + public static int calcPotionLiquidColor(ObjectContainer parCollection) { + int i = 3694022; + if (parCollection != null && !parCollection.isEmpty()) { + float f = 0.0F; + float f1 = 0.0F; + float f2 = 0.0F; + float f3 = 0.0F; + + for (ObjectCursor potioneffect_ : parCollection) { + PotionEffect potioneffect = potioneffect_.value; + if (potioneffect.getIsShowParticles()) { + int j = Potion.potionTypes[potioneffect.getPotionID()].getLiquidColor(); + + for (int k = 0; k <= potioneffect.getAmplifier(); ++k) { + f += (float) (j >> 16 & 255) / 255.0F; + f1 += (float) (j >> 8 & 255) / 255.0F; + f2 += (float) (j >> 0 & 255) / 255.0F; + ++f3; + } + } + } + + if (f3 == 0.0F) { + return 0; + } else { + f = f / f3 * 255.0F; + f1 = f1 / f3 * 255.0F; + f2 = f2 / f3 * 255.0F; + return (int) f << 16 | (int) f1 << 8 | (int) f2; + } + } else { + return i; + } + } + /**+ * Check whether a {@link Collection}<{@link PotionEffect}> are * all ambient. @@ -147,18 +188,32 @@ public class PotionHelper { return true; } + /**+ + * Check whether a {@link Collection}<{@link PotionEffect}> are + * all ambient. + */ + public static boolean getAreAmbient(ObjectContainer potionEffects) { + for (ObjectCursor potioneffect : potionEffects) { + if (!potioneffect.value.getIsAmbient()) { + return false; + } + } + + return true; + } + /**+ * Given a potion data value, get the associated liquid color * (optionally bypassing the cache) */ public static int getLiquidColor(int dataValue, boolean bypassCache) { - Integer integer = IntegerCache.func_181756_a(dataValue); if (!bypassCache) { - if (DATAVALUE_COLORS.containsKey(integer)) { - return ((Integer) DATAVALUE_COLORS.get(integer)).intValue(); + int i = DATAVALUE_COLORS.getOrDefault(dataValue, -1); + if (i != -1) { + return i; } else { - int i = calcPotionLiquidColor(getPotionEffects(integer.intValue(), false)); - DATAVALUE_COLORS.put(integer, Integer.valueOf(i)); + i = calcPotionLiquidColor(getPotionEffects(dataValue, false)); + DATAVALUE_COLORS.put(dataValue, i); return i; } } else { @@ -166,7 +221,7 @@ public class PotionHelper { * Given a {@link Collection}<{@link PotionEffect}> will return * an Integer color. */ - return calcPotionLiquidColor(getPotionEffects(integer.intValue(), true)); + return calcPotionLiquidColor(getPotionEffects(dataValue, true)); } } @@ -349,12 +404,12 @@ public class PotionHelper { for (int k = 0; k < Potion.potionTypes.length; ++k) { Potion potion = Potion.potionTypes[k]; if (potion != null && (!potion.isUsable() || parFlag)) { - String s = (String) potionRequirements.get(Integer.valueOf(potion.getId())); + String s = potionRequirements.get(potion.getId()); if (s != null) { int i = parsePotionEffects(s, 0, s.length(), parInt1); if (i > 0) { int j = 0; - String s1 = (String) potionAmplifiers.get(Integer.valueOf(potion.getId())); + String s1 = potionAmplifiers.get(potion.getId()); if (s1 != null) { j = parsePotionEffects(s1, 0, s1.length(), parInt1); if (j < 0) { diff --git a/src/game/java/net/minecraft/scoreboard/GoalColor.java b/src/game/java/net/minecraft/scoreboard/GoalColor.java index c1494f46..3d7b041f 100755 --- a/src/game/java/net/minecraft/scoreboard/GoalColor.java +++ b/src/game/java/net/minecraft/scoreboard/GoalColor.java @@ -11,7 +11,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/scoreboard/IScoreObjectiveCriteria.java b/src/game/java/net/minecraft/scoreboard/IScoreObjectiveCriteria.java index 66b33754..4a1eb3a7 100755 --- a/src/game/java/net/minecraft/scoreboard/IScoreObjectiveCriteria.java +++ b/src/game/java/net/minecraft/scoreboard/IScoreObjectiveCriteria.java @@ -14,7 +14,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/scoreboard/Score.java b/src/game/java/net/minecraft/scoreboard/Score.java index 17eb6861..053b0a05 100755 --- a/src/game/java/net/minecraft/scoreboard/Score.java +++ b/src/game/java/net/minecraft/scoreboard/Score.java @@ -11,7 +11,7 @@ import net.minecraft.entity.player.EntityPlayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/scoreboard/ScoreDummyCriteria.java b/src/game/java/net/minecraft/scoreboard/ScoreDummyCriteria.java index 46627e0d..087531f4 100755 --- a/src/game/java/net/minecraft/scoreboard/ScoreDummyCriteria.java +++ b/src/game/java/net/minecraft/scoreboard/ScoreDummyCriteria.java @@ -10,7 +10,7 @@ import net.minecraft.entity.player.EntityPlayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/scoreboard/ScoreHealthCriteria.java b/src/game/java/net/minecraft/scoreboard/ScoreHealthCriteria.java index 177ff284..0ef3ca6d 100755 --- a/src/game/java/net/minecraft/scoreboard/ScoreHealthCriteria.java +++ b/src/game/java/net/minecraft/scoreboard/ScoreHealthCriteria.java @@ -11,7 +11,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/scoreboard/ScoreObjective.java b/src/game/java/net/minecraft/scoreboard/ScoreObjective.java index da13e85e..e35ff501 100755 --- a/src/game/java/net/minecraft/scoreboard/ScoreObjective.java +++ b/src/game/java/net/minecraft/scoreboard/ScoreObjective.java @@ -9,7 +9,7 @@ import net.minecraft.client.Minecraft; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/scoreboard/ScorePlayerTeam.java b/src/game/java/net/minecraft/scoreboard/ScorePlayerTeam.java index 164b71a0..a18d1e80 100755 --- a/src/game/java/net/minecraft/scoreboard/ScorePlayerTeam.java +++ b/src/game/java/net/minecraft/scoreboard/ScorePlayerTeam.java @@ -13,7 +13,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/scoreboard/Scoreboard.java b/src/game/java/net/minecraft/scoreboard/Scoreboard.java index 22aa0994..e6562ae0 100755 --- a/src/game/java/net/minecraft/scoreboard/Scoreboard.java +++ b/src/game/java/net/minecraft/scoreboard/Scoreboard.java @@ -19,7 +19,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/scoreboard/ScoreboardSaveData.java b/src/game/java/net/minecraft/scoreboard/ScoreboardSaveData.java index 99ccc5f6..cb03c4c5 100755 --- a/src/game/java/net/minecraft/scoreboard/ScoreboardSaveData.java +++ b/src/game/java/net/minecraft/scoreboard/ScoreboardSaveData.java @@ -14,7 +14,7 @@ import net.minecraft.world.WorldSavedData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/scoreboard/ServerScoreboard.java b/src/game/java/net/minecraft/scoreboard/ServerScoreboard.java index 0c3d779f..17d021ec 100755 --- a/src/game/java/net/minecraft/scoreboard/ServerScoreboard.java +++ b/src/game/java/net/minecraft/scoreboard/ServerScoreboard.java @@ -20,7 +20,7 @@ import net.minecraft.server.MinecraftServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/scoreboard/Team.java b/src/game/java/net/minecraft/scoreboard/Team.java index 13a6775c..61044903 100755 --- a/src/game/java/net/minecraft/scoreboard/Team.java +++ b/src/game/java/net/minecraft/scoreboard/Team.java @@ -11,7 +11,7 @@ import com.google.common.collect.Maps; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/server/MinecraftServer.java b/src/game/java/net/minecraft/server/MinecraftServer.java index db5cee0c..631a6dec 100755 --- a/src/game/java/net/minecraft/server/MinecraftServer.java +++ b/src/game/java/net/minecraft/server/MinecraftServer.java @@ -55,7 +55,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/server/management/ItemInWorldManager.java b/src/game/java/net/minecraft/server/management/ItemInWorldManager.java index 8a4060d7..efe34faa 100755 --- a/src/game/java/net/minecraft/server/management/ItemInWorldManager.java +++ b/src/game/java/net/minecraft/server/management/ItemInWorldManager.java @@ -26,7 +26,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/server/management/LowerStringMap.java b/src/game/java/net/minecraft/server/management/LowerStringMap.java index bdde0f92..7b4e29d2 100755 --- a/src/game/java/net/minecraft/server/management/LowerStringMap.java +++ b/src/game/java/net/minecraft/server/management/LowerStringMap.java @@ -12,7 +12,7 @@ import com.google.common.collect.Maps; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/server/management/PlayerManager.java b/src/game/java/net/minecraft/server/management/PlayerManager.java index 447cee71..8257a5fb 100755 --- a/src/game/java/net/minecraft/server/management/PlayerManager.java +++ b/src/game/java/net/minecraft/server/management/PlayerManager.java @@ -1,7 +1,10 @@ package net.minecraft.server.management; +import com.carrotsearch.hppc.LongHashSet; +import com.carrotsearch.hppc.LongObjectHashMap; +import com.carrotsearch.hppc.LongObjectMap; +import com.carrotsearch.hppc.LongSet; import com.google.common.collect.Lists; -import java.util.ArrayList; import java.util.List; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.network.Packet; @@ -10,7 +13,6 @@ import net.minecraft.network.play.server.S22PacketMultiBlockChange; import net.minecraft.network.play.server.S23PacketBlockChange; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.BlockPos; -import net.minecraft.util.LongHashMap; import net.minecraft.util.MathHelper; import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.WorldProvider; @@ -25,7 +27,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -49,7 +51,7 @@ public class PlayerManager { /**+ * the hash of all playerInstances created */ - private final LongHashMap playerInstances = new LongHashMap(); + private final LongObjectMap playerInstances = new LongObjectHashMap<>(); /**+ * the playerInstances(chunks) that need to be updated */ @@ -112,7 +114,7 @@ public class PlayerManager { public boolean hasPlayerInstance(int chunkX, int chunkZ) { long i = (long) chunkX + 2147483647L | (long) chunkZ + 2147483647L << 32; - return this.playerInstances.getValueByKey(i) != null; + return this.playerInstances.get(i) != null; } /**+ @@ -121,11 +123,10 @@ public class PlayerManager { */ private PlayerManager.PlayerInstance getPlayerInstance(int chunkX, int chunkZ, boolean createIfAbsent) { long i = (long) chunkX + 2147483647L | (long) chunkZ + 2147483647L << 32; - PlayerManager.PlayerInstance playermanager$playerinstance = (PlayerManager.PlayerInstance) this.playerInstances - .getValueByKey(i); + PlayerManager.PlayerInstance playermanager$playerinstance = this.playerInstances.get(i); if (playermanager$playerinstance == null && createIfAbsent) { playermanager$playerinstance = new PlayerManager.PlayerInstance(chunkX, chunkZ); - this.playerInstances.add(i, playermanager$playerinstance); + this.playerInstances.put(i, playermanager$playerinstance); this.playerInstanceList.add(playermanager$playerinstance); } @@ -167,14 +168,14 @@ public class PlayerManager { * that are not in viewing range of the player. */ public void filterChunkLoadQueue(EntityPlayerMP player) { - ArrayList arraylist = Lists.newArrayList(player.loadedChunks); + LongSet arraylist = new LongHashSet(player.loadedChunks); int i = 0; int j = this.playerViewRadius; int k = (int) player.posX >> 4; int l = (int) player.posZ >> 4; int i1 = 0; int j1 = 0; - ChunkCoordIntPair chunkcoordintpair = this.getPlayerInstance(k, l, true).chunkCoords; + long chunkcoordintpair = this.getPlayerInstance(k, l, true).chunkCoordsHash; player.loadedChunks.clear(); if (arraylist.contains(chunkcoordintpair)) { player.loadedChunks.add(chunkcoordintpair); @@ -187,7 +188,7 @@ public class PlayerManager { for (int i2 = 0; i2 < k1; ++i2) { i1 += aint[0]; j1 += aint[1]; - chunkcoordintpair = this.getPlayerInstance(k + i1, l + j1, true).chunkCoords; + chunkcoordintpair = this.getPlayerInstance(k + i1, l + j1, true).chunkCoordsHash; if (arraylist.contains(chunkcoordintpair)) { player.loadedChunks.add(chunkcoordintpair); } @@ -200,7 +201,7 @@ public class PlayerManager { for (int j2 = 0; j2 < j * 2; ++j2) { i1 += this.xzDirectionsConst[i][0]; j1 += this.xzDirectionsConst[i][1]; - chunkcoordintpair = this.getPlayerInstance(k + i1, l + j1, true).chunkCoords; + chunkcoordintpair = this.getPlayerInstance(k + i1, l + j1, true).chunkCoordsHash; if (arraylist.contains(chunkcoordintpair)) { player.loadedChunks.add(chunkcoordintpair); } @@ -282,7 +283,7 @@ public class PlayerManager { PlayerManager.PlayerInstance playermanager$playerinstance = this.getPlayerInstance(chunkX, chunkZ, false); return playermanager$playerinstance != null && playermanager$playerinstance.playersWatchingChunk.contains(player) - && !player.loadedChunks.contains(playermanager$playerinstance.chunkCoords); + && !player.loadedChunks.contains(playermanager$playerinstance.chunkCoordsHash); } public void setPlayerViewRadius(int radius) { @@ -330,6 +331,7 @@ public class PlayerManager { class PlayerInstance { private final List playersWatchingChunk = Lists.newArrayList(); private final ChunkCoordIntPair chunkCoords; + private final long chunkCoordsHash; private short[] locationOfBlockChange = new short[64]; private int numBlocksToUpdate; private int flagsYAreasToUpdate; @@ -337,6 +339,7 @@ public class PlayerManager { public PlayerInstance(int chunkX, int chunkZ) { this.chunkCoords = new ChunkCoordIntPair(chunkX, chunkZ); + this.chunkCoordsHash = ChunkCoordIntPair.chunkXZ2Int(chunkX, chunkZ); PlayerManager.this.getWorldServer().theChunkProviderServer.loadChunk(chunkX, chunkZ); } @@ -355,7 +358,7 @@ public class PlayerManager { } this.playersWatchingChunk.add(player); - player.loadedChunks.add(this.chunkCoords); + player.loadedChunks.add(this.chunkCoordsHash); } } @@ -371,7 +374,7 @@ public class PlayerManager { } this.playersWatchingChunk.remove(player); - player.loadedChunks.remove(this.chunkCoords); + player.loadedChunks.removeAll(this.chunkCoordsHash); if (this.playersWatchingChunk.isEmpty()) { long i = (long) this.chunkCoords.chunkXPos + 2147483647L | (long) this.chunkCoords.chunkZPos + 2147483647L << 32; @@ -423,7 +426,7 @@ public class PlayerManager { public void sendToAllPlayersWatchingChunk(Packet thePacket) { for (int i = 0; i < this.playersWatchingChunk.size(); ++i) { EntityPlayerMP entityplayermp = (EntityPlayerMP) this.playersWatchingChunk.get(i); - if (!entityplayermp.loadedChunks.contains(this.chunkCoords)) { + if (!entityplayermp.loadedChunks.contains(this.chunkCoordsHash)) { entityplayermp.playerNetServerHandler.sendPacket(thePacket); } } diff --git a/src/game/java/net/minecraft/server/management/ServerConfigurationManager.java b/src/game/java/net/minecraft/server/management/ServerConfigurationManager.java index adabb031..e929b97a 100755 --- a/src/game/java/net/minecraft/server/management/ServerConfigurationManager.java +++ b/src/game/java/net/minecraft/server/management/ServerConfigurationManager.java @@ -1,5 +1,6 @@ package net.minecraft.server.management; +import com.carrotsearch.hppc.cursors.ObjectCursor; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -77,7 +78,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -175,8 +176,8 @@ public abstract class ServerConfigurationManager { playerIn.loadResourcePack(this.mcServer.getResourcePackUrl(), this.mcServer.getResourcePackHash()); } - for (PotionEffect potioneffect : playerIn.getActivePotionEffects()) { - nethandlerplayserver.sendPacket(new S1DPacketEntityEffect(playerIn.getEntityId(), potioneffect)); + for (ObjectCursor potioneffect : playerIn.getActivePotionEffects()) { + nethandlerplayserver.sendPacket(new S1DPacketEntityEffect(playerIn.getEntityId(), potioneffect.value)); } playerIn.addSelfToInternalCraftingInventory(); @@ -513,8 +514,9 @@ public abstract class ServerConfigurationManager { this.updateTimeAndWeatherForPlayer(playerIn, worldserver1); this.syncPlayerInventory(playerIn); - for (PotionEffect potioneffect : playerIn.getActivePotionEffects()) { - playerIn.playerNetServerHandler.sendPacket(new S1DPacketEntityEffect(playerIn.getEntityId(), potioneffect)); + for (ObjectCursor potioneffect : playerIn.getActivePotionEffects()) { + playerIn.playerNetServerHandler + .sendPacket(new S1DPacketEntityEffect(playerIn.getEntityId(), potioneffect.value)); } } @@ -890,12 +892,14 @@ public abstract class ServerConfigurationManager { public void setViewDistance(int distance) { this.viewDistance = distance; + int entityViewDist = getEntityViewDistance(); if (this.mcServer.worldServers != null) { WorldServer[] srv = this.mcServer.worldServers; for (int i = 0; i < srv.length; ++i) { WorldServer worldserver = srv[i]; if (worldserver != null) { worldserver.getPlayerManager().setPlayerViewRadius(distance); + worldserver.getEntityTracker().updateMaxTrackingThreshold(entityViewDist); } } } diff --git a/src/game/java/net/minecraft/server/network/NetHandlerLoginServer.java b/src/game/java/net/minecraft/server/network/NetHandlerLoginServer.java index 774ff124..46fd2c1e 100755 --- a/src/game/java/net/minecraft/server/network/NetHandlerLoginServer.java +++ b/src/game/java/net/minecraft/server/network/NetHandlerLoginServer.java @@ -34,7 +34,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/stats/Achievement.java b/src/game/java/net/minecraft/stats/Achievement.java index 4ac5c242..95ccb162 100755 --- a/src/game/java/net/minecraft/stats/Achievement.java +++ b/src/game/java/net/minecraft/stats/Achievement.java @@ -17,7 +17,7 @@ import net.minecraft.util.StatCollector; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/stats/AchievementList.java b/src/game/java/net/minecraft/stats/AchievementList.java index 9d5f5e99..df706f16 100755 --- a/src/game/java/net/minecraft/stats/AchievementList.java +++ b/src/game/java/net/minecraft/stats/AchievementList.java @@ -15,7 +15,7 @@ import net.minecraft.util.JsonSerializableSet; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/stats/IStatStringFormat.java b/src/game/java/net/minecraft/stats/IStatStringFormat.java index 7e0e58c3..5076c272 100755 --- a/src/game/java/net/minecraft/stats/IStatStringFormat.java +++ b/src/game/java/net/minecraft/stats/IStatStringFormat.java @@ -6,7 +6,7 @@ package net.minecraft.stats; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/stats/IStatType.java b/src/game/java/net/minecraft/stats/IStatType.java index f5f79e48..3a062b43 100755 --- a/src/game/java/net/minecraft/stats/IStatType.java +++ b/src/game/java/net/minecraft/stats/IStatType.java @@ -6,7 +6,7 @@ package net.minecraft.stats; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/stats/ObjectiveStat.java b/src/game/java/net/minecraft/stats/ObjectiveStat.java index 71c6f2ec..009e36c5 100755 --- a/src/game/java/net/minecraft/stats/ObjectiveStat.java +++ b/src/game/java/net/minecraft/stats/ObjectiveStat.java @@ -8,7 +8,7 @@ import net.minecraft.scoreboard.ScoreDummyCriteria; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/stats/StatBase.java b/src/game/java/net/minecraft/stats/StatBase.java index ea5b82fa..c6bfcae5 100755 --- a/src/game/java/net/minecraft/stats/StatBase.java +++ b/src/game/java/net/minecraft/stats/StatBase.java @@ -18,7 +18,7 @@ import net.minecraft.util.IJsonSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/stats/StatBasic.java b/src/game/java/net/minecraft/stats/StatBasic.java index fcd3ae81..b8762a03 100755 --- a/src/game/java/net/minecraft/stats/StatBasic.java +++ b/src/game/java/net/minecraft/stats/StatBasic.java @@ -8,7 +8,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/stats/StatCrafting.java b/src/game/java/net/minecraft/stats/StatCrafting.java index 949617d1..29853f29 100755 --- a/src/game/java/net/minecraft/stats/StatCrafting.java +++ b/src/game/java/net/minecraft/stats/StatCrafting.java @@ -10,7 +10,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/stats/StatFileWriter.java b/src/game/java/net/minecraft/stats/StatFileWriter.java index 6254facb..d1ad8779 100755 --- a/src/game/java/net/minecraft/stats/StatFileWriter.java +++ b/src/game/java/net/minecraft/stats/StatFileWriter.java @@ -14,7 +14,7 @@ import net.minecraft.util.TupleIntJsonSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/stats/StatList.java b/src/game/java/net/minecraft/stats/StatList.java index c04e8bfc..cd27105e 100755 --- a/src/game/java/net/minecraft/stats/StatList.java +++ b/src/game/java/net/minecraft/stats/StatList.java @@ -26,7 +26,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/stats/StatisticsFile.java b/src/game/java/net/minecraft/stats/StatisticsFile.java index e5164ffa..2de7f2af 100755 --- a/src/game/java/net/minecraft/stats/StatisticsFile.java +++ b/src/game/java/net/minecraft/stats/StatisticsFile.java @@ -1,5 +1,7 @@ package net.minecraft.stats; +import com.carrotsearch.hppc.ObjectIntHashMap; +import com.carrotsearch.hppc.ObjectIntMap; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import java.util.HashMap; @@ -27,7 +29,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -187,12 +189,12 @@ public class StatisticsFile extends StatFileWriter { public void func_150876_a(EntityPlayerMP parEntityPlayerMP) { int i = this.mcServer.getTickCounter(); - HashMap hashmap = Maps.newHashMap(); + ObjectIntMap hashmap = new ObjectIntHashMap<>(); if (this.field_150886_g || i - this.field_150885_f > 300) { this.field_150885_f = i; for (StatBase statbase : this.func_150878_c()) { - hashmap.put(statbase, Integer.valueOf(this.readStat(statbase))); + hashmap.put(statbase, this.readStat(statbase)); } } @@ -200,12 +202,12 @@ public class StatisticsFile extends StatFileWriter { } public void sendAchievements(EntityPlayerMP player) { - HashMap hashmap = Maps.newHashMap(); + ObjectIntMap hashmap = new ObjectIntHashMap<>(); for (int i = 0, l = AchievementList.achievementList.size(); i < l; ++i) { Achievement achievement = AchievementList.achievementList.get(i); if (this.hasAchievementUnlocked(achievement)) { - hashmap.put(achievement, Integer.valueOf(this.readStat(achievement))); + hashmap.put(achievement, this.readStat(achievement)); this.field_150888_e.remove(achievement); } } diff --git a/src/game/java/net/minecraft/tileentity/IHopper.java b/src/game/java/net/minecraft/tileentity/IHopper.java index ed95f3cc..19277dc1 100755 --- a/src/game/java/net/minecraft/tileentity/IHopper.java +++ b/src/game/java/net/minecraft/tileentity/IHopper.java @@ -9,7 +9,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/MobSpawnerBaseLogic.java b/src/game/java/net/minecraft/tileentity/MobSpawnerBaseLogic.java index 90d88e36..52835e13 100755 --- a/src/game/java/net/minecraft/tileentity/MobSpawnerBaseLogic.java +++ b/src/game/java/net/minecraft/tileentity/MobSpawnerBaseLogic.java @@ -26,7 +26,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntity.java b/src/game/java/net/minecraft/tileentity/TileEntity.java index de99e46f..5cda6cc0 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntity.java +++ b/src/game/java/net/minecraft/tileentity/TileEntity.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityBanner.java b/src/game/java/net/minecraft/tileentity/TileEntityBanner.java index 8f676e1e..ea3fb7f4 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityBanner.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityBanner.java @@ -21,7 +21,7 @@ import net.minecraft.network.play.server.S35PacketUpdateTileEntity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityBeacon.java b/src/game/java/net/minecraft/tileentity/TileEntityBeacon.java index 2dab48a1..5d4158c7 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityBeacon.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityBeacon.java @@ -33,7 +33,7 @@ import net.minecraft.util.ITickable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityBrewingStand.java b/src/game/java/net/minecraft/tileentity/TileEntityBrewingStand.java index 14f7c87f..1979cca9 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityBrewingStand.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityBrewingStand.java @@ -25,7 +25,7 @@ import net.minecraft.util.ITickable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityChest.java b/src/game/java/net/minecraft/tileentity/TileEntityChest.java index 60ddfcf8..e03a4254 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityChest.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityChest.java @@ -24,7 +24,7 @@ import net.minecraft.util.ITickable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityCommandBlock.java b/src/game/java/net/minecraft/tileentity/TileEntityCommandBlock.java index 02690217..64adc1c7 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityCommandBlock.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityCommandBlock.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityComparator.java b/src/game/java/net/minecraft/tileentity/TileEntityComparator.java index 0d8dc626..ba7abd96 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityComparator.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityComparator.java @@ -8,7 +8,7 @@ import net.minecraft.nbt.NBTTagCompound; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityDaylightDetector.java b/src/game/java/net/minecraft/tileentity/TileEntityDaylightDetector.java index 7a36af3e..1641451b 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityDaylightDetector.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityDaylightDetector.java @@ -9,7 +9,7 @@ import net.minecraft.util.ITickable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityDispenser.java b/src/game/java/net/minecraft/tileentity/TileEntityDispenser.java index 69dd8956..6c015b4c 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityDispenser.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityDispenser.java @@ -17,7 +17,7 @@ import net.minecraft.nbt.NBTTagList; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityDropper.java b/src/game/java/net/minecraft/tileentity/TileEntityDropper.java index ec46a26c..f6d368e4 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityDropper.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityDropper.java @@ -6,7 +6,7 @@ package net.minecraft.tileentity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityEnchantmentTable.java b/src/game/java/net/minecraft/tileentity/TileEntityEnchantmentTable.java index 17cc7f9e..7ccc8a7b 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityEnchantmentTable.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityEnchantmentTable.java @@ -20,7 +20,7 @@ import net.minecraft.world.IInteractionObject; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityEndPortal.java b/src/game/java/net/minecraft/tileentity/TileEntityEndPortal.java index 7f221329..7b83b486 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityEndPortal.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityEndPortal.java @@ -6,7 +6,7 @@ package net.minecraft.tileentity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityEnderChest.java b/src/game/java/net/minecraft/tileentity/TileEntityEnderChest.java index f424b073..37bf6f8e 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityEnderChest.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityEnderChest.java @@ -10,7 +10,7 @@ import net.minecraft.util.ITickable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityFlowerPot.java b/src/game/java/net/minecraft/tileentity/TileEntityFlowerPot.java index 15e2a6d3..e7401dee 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityFlowerPot.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityFlowerPot.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityFurnace.java b/src/game/java/net/minecraft/tileentity/TileEntityFurnace.java index 10d37bb2..57c2742f 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityFurnace.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityFurnace.java @@ -31,7 +31,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityHopper.java b/src/game/java/net/minecraft/tileentity/TileEntityHopper.java index d98136ea..6353c0f2 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityHopper.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityHopper.java @@ -29,7 +29,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityLockable.java b/src/game/java/net/minecraft/tileentity/TileEntityLockable.java index bd0bec24..03ec46df 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityLockable.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityLockable.java @@ -14,7 +14,7 @@ import net.minecraft.world.LockCode; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityMobSpawner.java b/src/game/java/net/minecraft/tileentity/TileEntityMobSpawner.java index 9ec237d8..b50b2bc9 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityMobSpawner.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityMobSpawner.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityNote.java b/src/game/java/net/minecraft/tileentity/TileEntityNote.java index bd69787b..1646f56c 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityNote.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityNote.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntityPiston.java b/src/game/java/net/minecraft/tileentity/TileEntityPiston.java index bd64be81..d9c9f1e4 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityPiston.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityPiston.java @@ -19,7 +19,7 @@ import net.minecraft.util.ITickable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntitySign.java b/src/game/java/net/minecraft/tileentity/TileEntitySign.java index cc54715f..2ef0198c 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntitySign.java +++ b/src/game/java/net/minecraft/tileentity/TileEntitySign.java @@ -28,7 +28,7 @@ import org.json.JSONException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/tileentity/TileEntitySkull.java b/src/game/java/net/minecraft/tileentity/TileEntitySkull.java index 89c04c21..bae6f047 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntitySkull.java +++ b/src/game/java/net/minecraft/tileentity/TileEntitySkull.java @@ -15,7 +15,7 @@ import net.minecraft.util.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/AxisAlignedBB.java b/src/game/java/net/minecraft/util/AxisAlignedBB.java index 06935453..ee775582 100755 --- a/src/game/java/net/minecraft/util/AxisAlignedBB.java +++ b/src/game/java/net/minecraft/util/AxisAlignedBB.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/BlockPos.java b/src/game/java/net/minecraft/util/BlockPos.java index becd0c73..9018f7e4 100755 --- a/src/game/java/net/minecraft/util/BlockPos.java +++ b/src/game/java/net/minecraft/util/BlockPos.java @@ -12,7 +12,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/Cartesian.java b/src/game/java/net/minecraft/util/Cartesian.java index 2320f280..2727e17f 100755 --- a/src/game/java/net/minecraft/util/Cartesian.java +++ b/src/game/java/net/minecraft/util/Cartesian.java @@ -19,7 +19,7 @@ import com.google.common.collect.UnmodifiableIterator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/ChatAllowedCharacters.java b/src/game/java/net/minecraft/util/ChatAllowedCharacters.java index f1d282bc..be1416f3 100755 --- a/src/game/java/net/minecraft/util/ChatAllowedCharacters.java +++ b/src/game/java/net/minecraft/util/ChatAllowedCharacters.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/ChatComponentProcessor.java b/src/game/java/net/minecraft/util/ChatComponentProcessor.java index 232a3248..848a3ad9 100755 --- a/src/game/java/net/minecraft/util/ChatComponentProcessor.java +++ b/src/game/java/net/minecraft/util/ChatComponentProcessor.java @@ -14,7 +14,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/ChatComponentScore.java b/src/game/java/net/minecraft/util/ChatComponentScore.java index b7dd9125..4dcc9dee 100755 --- a/src/game/java/net/minecraft/util/ChatComponentScore.java +++ b/src/game/java/net/minecraft/util/ChatComponentScore.java @@ -15,7 +15,7 @@ import net.lax1dude.eaglercraft.v1_8.HString; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/ChatComponentSelector.java b/src/game/java/net/minecraft/util/ChatComponentSelector.java index d665f0c9..92a58e1a 100755 --- a/src/game/java/net/minecraft/util/ChatComponentSelector.java +++ b/src/game/java/net/minecraft/util/ChatComponentSelector.java @@ -8,7 +8,7 @@ import java.util.List; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/ChatComponentStyle.java b/src/game/java/net/minecraft/util/ChatComponentStyle.java index b7a53dba..0ba3b4a8 100755 --- a/src/game/java/net/minecraft/util/ChatComponentStyle.java +++ b/src/game/java/net/minecraft/util/ChatComponentStyle.java @@ -13,7 +13,7 @@ import com.google.common.collect.Lists; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/ChatComponentText.java b/src/game/java/net/minecraft/util/ChatComponentText.java index 2fc6115a..a4ac0998 100755 --- a/src/game/java/net/minecraft/util/ChatComponentText.java +++ b/src/game/java/net/minecraft/util/ChatComponentText.java @@ -8,7 +8,7 @@ import java.util.List; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/ChatComponentTranslation.java b/src/game/java/net/minecraft/util/ChatComponentTranslation.java index aeda3e09..840da12b 100755 --- a/src/game/java/net/minecraft/util/ChatComponentTranslation.java +++ b/src/game/java/net/minecraft/util/ChatComponentTranslation.java @@ -18,7 +18,7 @@ import net.lax1dude.eaglercraft.v1_8.HString; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/ChatComponentTranslationFormatException.java b/src/game/java/net/minecraft/util/ChatComponentTranslationFormatException.java index c8143f24..95708431 100755 --- a/src/game/java/net/minecraft/util/ChatComponentTranslationFormatException.java +++ b/src/game/java/net/minecraft/util/ChatComponentTranslationFormatException.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.HString; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/ChatStyle.java b/src/game/java/net/minecraft/util/ChatStyle.java index 386fbe15..7009b48f 100755 --- a/src/game/java/net/minecraft/util/ChatStyle.java +++ b/src/game/java/net/minecraft/util/ChatStyle.java @@ -14,7 +14,7 @@ import net.minecraft.event.HoverEvent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/ClassInheritanceMultiMap.java b/src/game/java/net/minecraft/util/ClassInheritanceMultiMap.java index 70c1a2f3..7916525e 100755 --- a/src/game/java/net/minecraft/util/ClassInheritanceMultiMap.java +++ b/src/game/java/net/minecraft/util/ClassInheritanceMultiMap.java @@ -17,7 +17,7 @@ import com.google.common.collect.Sets; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/CombatEntry.java b/src/game/java/net/minecraft/util/CombatEntry.java index 3b2037f4..93ec982c 100755 --- a/src/game/java/net/minecraft/util/CombatEntry.java +++ b/src/game/java/net/minecraft/util/CombatEntry.java @@ -8,7 +8,7 @@ import net.minecraft.entity.EntityLivingBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/CombatTracker.java b/src/game/java/net/minecraft/util/CombatTracker.java index dab0c76a..90a2e9a9 100755 --- a/src/game/java/net/minecraft/util/CombatTracker.java +++ b/src/game/java/net/minecraft/util/CombatTracker.java @@ -17,7 +17,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/DamageSource.java b/src/game/java/net/minecraft/util/DamageSource.java index 7094f605..f7371ff2 100755 --- a/src/game/java/net/minecraft/util/DamageSource.java +++ b/src/game/java/net/minecraft/util/DamageSource.java @@ -13,7 +13,7 @@ import net.minecraft.world.Explosion; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/EnchantmentNameParts.java b/src/game/java/net/minecraft/util/EnchantmentNameParts.java index 02631043..98d9c8ce 100755 --- a/src/game/java/net/minecraft/util/EnchantmentNameParts.java +++ b/src/game/java/net/minecraft/util/EnchantmentNameParts.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/EntityDamageSource.java b/src/game/java/net/minecraft/util/EntityDamageSource.java index 7cfd8506..4f148b5a 100755 --- a/src/game/java/net/minecraft/util/EntityDamageSource.java +++ b/src/game/java/net/minecraft/util/EntityDamageSource.java @@ -11,7 +11,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/EntityDamageSourceIndirect.java b/src/game/java/net/minecraft/util/EntityDamageSourceIndirect.java index 968cc011..1b7ba2f7 100755 --- a/src/game/java/net/minecraft/util/EntityDamageSourceIndirect.java +++ b/src/game/java/net/minecraft/util/EntityDamageSourceIndirect.java @@ -10,7 +10,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/EntitySelectors.java b/src/game/java/net/minecraft/util/EntitySelectors.java index 0bfd26dc..0d18d67a 100755 --- a/src/game/java/net/minecraft/util/EntitySelectors.java +++ b/src/game/java/net/minecraft/util/EntitySelectors.java @@ -16,7 +16,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/EnumChatFormatting.java b/src/game/java/net/minecraft/util/EnumChatFormatting.java index a35843e6..37ee9da3 100755 --- a/src/game/java/net/minecraft/util/EnumChatFormatting.java +++ b/src/game/java/net/minecraft/util/EnumChatFormatting.java @@ -14,7 +14,7 @@ import com.google.common.collect.Maps; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/EnumFacing.java b/src/game/java/net/minecraft/util/EnumFacing.java index 7d19e70e..20fd18e5 100755 --- a/src/game/java/net/minecraft/util/EnumFacing.java +++ b/src/game/java/net/minecraft/util/EnumFacing.java @@ -14,7 +14,7 @@ import com.google.common.collect.Maps; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/EnumParticleTypes.java b/src/game/java/net/minecraft/util/EnumParticleTypes.java index b834b408..eac53302 100755 --- a/src/game/java/net/minecraft/util/EnumParticleTypes.java +++ b/src/game/java/net/minecraft/util/EnumParticleTypes.java @@ -1,10 +1,10 @@ package net.minecraft.util; import java.util.ArrayList; -import java.util.Map; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; /**+ * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. @@ -12,7 +12,7 @@ import com.google.common.collect.Maps; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -49,7 +49,7 @@ public enum EnumParticleTypes { private final int particleID; private final boolean shouldIgnoreRange; private final int argumentCount; - private static final Map PARTICLES = Maps.newHashMap(); + private static final IntObjectMap PARTICLES = new IntObjectHashMap<>(); private static final String[] PARTICLE_NAMES; private EnumParticleTypes(String particleNameIn, int particleIDIn, boolean parFlag, int argumentCountIn) { @@ -91,7 +91,7 @@ public enum EnumParticleTypes { * Gets the relative EnumParticleTypes by id. */ public static EnumParticleTypes getParticleFromId(int particleId) { - return (EnumParticleTypes) PARTICLES.get(Integer.valueOf(particleId)); + return PARTICLES.get(Integer.valueOf(particleId)); } static { diff --git a/src/game/java/net/minecraft/util/EnumWorldBlockLayer.java b/src/game/java/net/minecraft/util/EnumWorldBlockLayer.java index 306ae0e3..2472a9cc 100755 --- a/src/game/java/net/minecraft/util/EnumWorldBlockLayer.java +++ b/src/game/java/net/minecraft/util/EnumWorldBlockLayer.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/FoodStats.java b/src/game/java/net/minecraft/util/FoodStats.java index 06beb9d2..423f49f8 100755 --- a/src/game/java/net/minecraft/util/FoodStats.java +++ b/src/game/java/net/minecraft/util/FoodStats.java @@ -12,7 +12,7 @@ import net.minecraft.world.EnumDifficulty; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/FrameTimer.java b/src/game/java/net/minecraft/util/FrameTimer.java index 6dd30ef9..8b137e2b 100755 --- a/src/game/java/net/minecraft/util/FrameTimer.java +++ b/src/game/java/net/minecraft/util/FrameTimer.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/IChatComponent.java b/src/game/java/net/minecraft/util/IChatComponent.java index 6bfdc531..d540c226 100755 --- a/src/game/java/net/minecraft/util/IChatComponent.java +++ b/src/game/java/net/minecraft/util/IChatComponent.java @@ -15,7 +15,7 @@ import net.lax1dude.eaglercraft.v1_8.json.JSONTypeProvider; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/IJsonSerializable.java b/src/game/java/net/minecraft/util/IJsonSerializable.java index 8324b776..c45a70e8 100755 --- a/src/game/java/net/minecraft/util/IJsonSerializable.java +++ b/src/game/java/net/minecraft/util/IJsonSerializable.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/IObjectIntIterable.java b/src/game/java/net/minecraft/util/IObjectIntIterable.java index 62f2bcd6..c1562b35 100755 --- a/src/game/java/net/minecraft/util/IObjectIntIterable.java +++ b/src/game/java/net/minecraft/util/IObjectIntIterable.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/IProgressUpdate.java b/src/game/java/net/minecraft/util/IProgressUpdate.java index 015fa8cd..48e80df6 100755 --- a/src/game/java/net/minecraft/util/IProgressUpdate.java +++ b/src/game/java/net/minecraft/util/IProgressUpdate.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/IRegistry.java b/src/game/java/net/minecraft/util/IRegistry.java index bf239037..175be0e7 100755 --- a/src/game/java/net/minecraft/util/IRegistry.java +++ b/src/game/java/net/minecraft/util/IRegistry.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/IStringSerializable.java b/src/game/java/net/minecraft/util/IStringSerializable.java index 7301c90b..a024ce61 100755 --- a/src/game/java/net/minecraft/util/IStringSerializable.java +++ b/src/game/java/net/minecraft/util/IStringSerializable.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/IThreadListener.java b/src/game/java/net/minecraft/util/IThreadListener.java index 1bac31bf..8d634d6c 100755 --- a/src/game/java/net/minecraft/util/IThreadListener.java +++ b/src/game/java/net/minecraft/util/IThreadListener.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/ITickable.java b/src/game/java/net/minecraft/util/ITickable.java index f2c757d3..cbb0db01 100755 --- a/src/game/java/net/minecraft/util/ITickable.java +++ b/src/game/java/net/minecraft/util/ITickable.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/IntHashMap.java b/src/game/java/net/minecraft/util/IntHashMap.java deleted file mode 100755 index 83e4f72c..00000000 --- a/src/game/java/net/minecraft/util/IntHashMap.java +++ /dev/null @@ -1,265 +0,0 @@ -package net.minecraft.util; - -/**+ - * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. - * - * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" - * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team - * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ -public class IntHashMap { - /**+ - * An array of HashEntries representing the heads of hash slot - * lists - */ - private transient IntHashMap.Entry[] slots = new IntHashMap.Entry[16]; - private transient int count; - /**+ - * The grow threshold - */ - private int threshold = 12; - /**+ - * The scale factor used to determine when to grow the table - */ - private final float growFactor = 0.75F; - - /**+ - * Makes the passed in integer suitable for hashing by a number - * of shifts - */ - private static int computeHash(int integer) { - integer = integer ^ integer >>> 20 ^ integer >>> 12; - return integer ^ integer >>> 7 ^ integer >>> 4; - } - - /**+ - * Computes the index of the slot for the hash and slot count - * passed in. - */ - private static int getSlotIndex(int hash, int slotCount) { - return hash & slotCount - 1; - } - - /**+ - * Returns the object associated to a key - */ - public V lookup(int parInt1) { - int i = computeHash(parInt1); - - for (IntHashMap.Entry inthashmap$entry = this.slots[getSlotIndex(i, - this.slots.length)]; inthashmap$entry != null; inthashmap$entry = inthashmap$entry.nextEntry) { - if (inthashmap$entry.hashEntry == parInt1) { - return (V) inthashmap$entry.valueEntry; - } - } - - return (V) null; - } - - /**+ - * Returns true if this hash table contains the specified item. - */ - public boolean containsItem(int parInt1) { - return this.lookupEntry(parInt1) != null; - } - - /**+ - * Returns the internal entry for a key - */ - final IntHashMap.Entry lookupEntry(int parInt1) { - int i = computeHash(parInt1); - - for (IntHashMap.Entry inthashmap$entry = this.slots[getSlotIndex(i, - this.slots.length)]; inthashmap$entry != null; inthashmap$entry = inthashmap$entry.nextEntry) { - if (inthashmap$entry.hashEntry == parInt1) { - return inthashmap$entry; - } - } - - return null; - } - - /**+ - * Adds a key and associated value to this map - */ - public void addKey(int parInt1, V parObject) { - int i = computeHash(parInt1); - int j = getSlotIndex(i, this.slots.length); - - for (IntHashMap.Entry inthashmap$entry = this.slots[j]; inthashmap$entry != null; inthashmap$entry = inthashmap$entry.nextEntry) { - if (inthashmap$entry.hashEntry == parInt1) { - inthashmap$entry.valueEntry = parObject; - return; - } - } - - this.insert(i, parInt1, parObject, j); - } - - /**+ - * Increases the number of hash slots - */ - private void grow(int parInt1) { - IntHashMap.Entry[] ainthashmap$entry = this.slots; - int i = ainthashmap$entry.length; - if (i == 1073741824) { - this.threshold = Integer.MAX_VALUE; - } else { - IntHashMap.Entry[] ainthashmap$entry1 = new IntHashMap.Entry[parInt1]; - this.copyTo(ainthashmap$entry1); - this.slots = ainthashmap$entry1; - this.threshold = (int) ((float) parInt1 * this.growFactor); - } - } - - /**+ - * Copies the hash slots to a new array - */ - private void copyTo(IntHashMap.Entry[] parArrayOfEntry) { - IntHashMap.Entry[] ainthashmap$entry = this.slots; - int i = parArrayOfEntry.length; - - for (int j = 0; j < ainthashmap$entry.length; ++j) { - IntHashMap.Entry inthashmap$entry = ainthashmap$entry[j]; - if (inthashmap$entry != null) { - ainthashmap$entry[j] = null; - - while (true) { - IntHashMap.Entry inthashmap$entry1 = inthashmap$entry.nextEntry; - int k = getSlotIndex(inthashmap$entry.slotHash, i); - inthashmap$entry.nextEntry = parArrayOfEntry[k]; - parArrayOfEntry[k] = inthashmap$entry; - inthashmap$entry = inthashmap$entry1; - if (inthashmap$entry1 == null) { - break; - } - } - } - } - - } - - /**+ - * Removes the specified object from the map and returns it - */ - public V removeObject(int parInt1) { - IntHashMap.Entry inthashmap$entry = this.removeEntry(parInt1); - return (V) (inthashmap$entry == null ? null : inthashmap$entry.valueEntry); - } - - /**+ - * Removes the specified entry from the map and returns it - */ - final IntHashMap.Entry removeEntry(int parInt1) { - int i = computeHash(parInt1); - int j = getSlotIndex(i, this.slots.length); - IntHashMap.Entry inthashmap$entry = this.slots[j]; - - IntHashMap.Entry inthashmap$entry1; - IntHashMap.Entry inthashmap$entry2; - for (inthashmap$entry1 = inthashmap$entry; inthashmap$entry1 != null; inthashmap$entry1 = inthashmap$entry2) { - inthashmap$entry2 = inthashmap$entry1.nextEntry; - if (inthashmap$entry1.hashEntry == parInt1) { - --this.count; - if (inthashmap$entry == inthashmap$entry1) { - this.slots[j] = inthashmap$entry2; - } else { - inthashmap$entry.nextEntry = inthashmap$entry2; - } - - return inthashmap$entry1; - } - - inthashmap$entry = inthashmap$entry1; - } - - return inthashmap$entry1; - } - - /**+ - * Removes all entries from the map - */ - public void clearMap() { - IntHashMap.Entry[] ainthashmap$entry = this.slots; - - for (int i = 0; i < ainthashmap$entry.length; ++i) { - ainthashmap$entry[i] = null; - } - - this.count = 0; - } - - /**+ - * Adds an object to a slot - */ - private void insert(int parInt1, int parInt2, V parObject, int parInt3) { - IntHashMap.Entry inthashmap$entry = this.slots[parInt3]; - this.slots[parInt3] = new IntHashMap.Entry(parInt1, parInt2, parObject, inthashmap$entry); - if (this.count++ >= this.threshold) { - this.grow(2 * this.slots.length); - } - - } - - static class Entry { - final int hashEntry; - V valueEntry; - IntHashMap.Entry nextEntry; - final int slotHash; - - Entry(int parInt1, int parInt2, V parObject, IntHashMap.Entry parEntry) { - this.valueEntry = parObject; - this.nextEntry = parEntry; - this.hashEntry = parInt2; - this.slotHash = parInt1; - } - - public final int getHash() { - return this.hashEntry; - } - - public final V getValue() { - return this.valueEntry; - } - - public final boolean equals(Object object) { - if (!(object instanceof IntHashMap.Entry)) { - return false; - } else { - IntHashMap.Entry inthashmap$entry = (IntHashMap.Entry) object; - Integer integer = Integer.valueOf(this.getHash()); - Integer integer1 = Integer.valueOf(inthashmap$entry.getHash()); - if (integer == integer1 || integer != null && integer.equals(integer1)) { - Object object1 = this.getValue(); - Object object2 = inthashmap$entry.getValue(); - if (object1 == object2 || object1 != null && object1.equals(object2)) { - return true; - } - } - - return false; - } - } - - public final int hashCode() { - return IntHashMap.computeHash(this.hashEntry); - } - - public final String toString() { - return this.getHash() + "=" + this.getValue(); - } - } -} \ No newline at end of file diff --git a/src/game/java/net/minecraft/util/IntegerCache.java b/src/game/java/net/minecraft/util/IntegerCache.java index f052720c..332c727e 100755 --- a/src/game/java/net/minecraft/util/IntegerCache.java +++ b/src/game/java/net/minecraft/util/IntegerCache.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/JsonSerializableSet.java b/src/game/java/net/minecraft/util/JsonSerializableSet.java index f06f4ea3..ecfdd0d4 100755 --- a/src/game/java/net/minecraft/util/JsonSerializableSet.java +++ b/src/game/java/net/minecraft/util/JsonSerializableSet.java @@ -13,7 +13,7 @@ import com.google.common.collect.Sets; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/LazyLoadBase.java b/src/game/java/net/minecraft/util/LazyLoadBase.java index 8382aef8..f448fbd8 100755 --- a/src/game/java/net/minecraft/util/LazyLoadBase.java +++ b/src/game/java/net/minecraft/util/LazyLoadBase.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/LoggingPrintStream.java b/src/game/java/net/minecraft/util/LoggingPrintStream.java index 8e564736..04077d98 100755 --- a/src/game/java/net/minecraft/util/LoggingPrintStream.java +++ b/src/game/java/net/minecraft/util/LoggingPrintStream.java @@ -13,7 +13,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/LongHashMap.java b/src/game/java/net/minecraft/util/LongHashMap.java deleted file mode 100755 index 74abb5a3..00000000 --- a/src/game/java/net/minecraft/util/LongHashMap.java +++ /dev/null @@ -1,269 +0,0 @@ -package net.minecraft.util; - -/**+ - * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. - * - * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" - * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team - * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ -public class LongHashMap { - /**+ - * the array of all elements in the hash - */ - private transient LongHashMap.Entry[] hashArray = new LongHashMap.Entry[4096]; - private transient int numHashElements; - private int mask; - /**+ - * the maximum amount of elements in the hash (probably 3/4 the - * size due to meh hashing function) - */ - private int capacity = 3072; - /**+ - * percent of the hasharray that can be used without hash - * colliding probably - */ - private final float percentUseable = 0.75F; - private transient volatile int modCount; - - public LongHashMap() { - this.mask = this.hashArray.length - 1; - } - - /**+ - * returns the hashed key given the original key - */ - private static int getHashedKey(long originalKey) { - /**+ - * the hash function - */ - return hash((int) (originalKey ^ originalKey >>> 32)); - } - - /**+ - * the hash function - */ - private static int hash(int integer) { - integer = integer ^ integer >>> 20 ^ integer >>> 12; - return integer ^ integer >>> 7 ^ integer >>> 4; - } - - /**+ - * gets the index in the hash given the array length and the - * hashed key - */ - private static int getHashIndex(int parInt1, int parInt2) { - return parInt1 & parInt2; - } - - public int getNumHashElements() { - return this.numHashElements; - } - - /**+ - * get the value from the map given the key - */ - public V getValueByKey(long parLong1) { - int i = getHashedKey(parLong1); - - for (LongHashMap.Entry longhashmap$entry = this.hashArray[getHashIndex(i, - this.mask)]; longhashmap$entry != null; longhashmap$entry = longhashmap$entry.nextEntry) { - if (longhashmap$entry.key == parLong1) { - return (V) longhashmap$entry.value; - } - } - - return (V) null; - } - - public boolean containsItem(long parLong1) { - return this.getEntry(parLong1) != null; - } - - final LongHashMap.Entry getEntry(long parLong1) { - int i = getHashedKey(parLong1); - - for (LongHashMap.Entry longhashmap$entry = this.hashArray[getHashIndex(i, - this.mask)]; longhashmap$entry != null; longhashmap$entry = longhashmap$entry.nextEntry) { - if (longhashmap$entry.key == parLong1) { - return longhashmap$entry; - } - } - - return null; - } - - /**+ - * Add a key-value pair. - */ - public void add(long parLong1, V parObject) { - int i = getHashedKey(parLong1); - int j = getHashIndex(i, this.mask); - - for (LongHashMap.Entry longhashmap$entry = this.hashArray[j]; longhashmap$entry != null; longhashmap$entry = longhashmap$entry.nextEntry) { - if (longhashmap$entry.key == parLong1) { - longhashmap$entry.value = parObject; - return; - } - } - - ++this.modCount; - this.createKey(i, parLong1, parObject, j); - } - - /**+ - * resizes the table - */ - private void resizeTable(int parInt1) { - LongHashMap.Entry[] alonghashmap$entry = this.hashArray; - int i = alonghashmap$entry.length; - if (i == 1073741824) { - this.capacity = Integer.MAX_VALUE; - } else { - LongHashMap.Entry[] alonghashmap$entry1 = new LongHashMap.Entry[parInt1]; - this.copyHashTableTo(alonghashmap$entry1); - this.hashArray = alonghashmap$entry1; - this.mask = this.hashArray.length - 1; - this.capacity = (int) ((float) parInt1 * this.percentUseable); - } - } - - /**+ - * copies the hash table to the specified array - */ - private void copyHashTableTo(LongHashMap.Entry[] parArrayOfEntry) { - LongHashMap.Entry[] alonghashmap$entry = this.hashArray; - int i = parArrayOfEntry.length; - - for (int j = 0; j < alonghashmap$entry.length; ++j) { - LongHashMap.Entry longhashmap$entry = alonghashmap$entry[j]; - if (longhashmap$entry != null) { - alonghashmap$entry[j] = null; - - while (true) { - LongHashMap.Entry longhashmap$entry1 = longhashmap$entry.nextEntry; - int k = getHashIndex(longhashmap$entry.hash, i - 1); - longhashmap$entry.nextEntry = parArrayOfEntry[k]; - parArrayOfEntry[k] = longhashmap$entry; - longhashmap$entry = longhashmap$entry1; - if (longhashmap$entry1 == null) { - break; - } - } - } - } - - } - - /**+ - * calls the removeKey method and returns removed object - */ - public V remove(long parLong1) { - LongHashMap.Entry longhashmap$entry = this.removeKey(parLong1); - return (V) (longhashmap$entry == null ? null : longhashmap$entry.value); - } - - /**+ - * removes the key from the hash linked list - */ - final LongHashMap.Entry removeKey(long parLong1) { - int i = getHashedKey(parLong1); - int j = getHashIndex(i, this.mask); - LongHashMap.Entry longhashmap$entry = this.hashArray[j]; - - LongHashMap.Entry longhashmap$entry1; - LongHashMap.Entry longhashmap$entry2; - for (longhashmap$entry1 = longhashmap$entry; longhashmap$entry1 != null; longhashmap$entry1 = longhashmap$entry2) { - longhashmap$entry2 = longhashmap$entry1.nextEntry; - if (longhashmap$entry1.key == parLong1) { - ++this.modCount; - --this.numHashElements; - if (longhashmap$entry == longhashmap$entry1) { - this.hashArray[j] = longhashmap$entry2; - } else { - longhashmap$entry.nextEntry = longhashmap$entry2; - } - - return longhashmap$entry1; - } - - longhashmap$entry = longhashmap$entry1; - } - - return longhashmap$entry1; - } - - /**+ - * creates the key in the hash table - */ - private void createKey(int parInt1, long parLong1, V parObject, int parInt2) { - LongHashMap.Entry longhashmap$entry = this.hashArray[parInt2]; - this.hashArray[parInt2] = new LongHashMap.Entry(parInt1, parLong1, parObject, longhashmap$entry); - if (this.numHashElements++ >= this.capacity) { - this.resizeTable(2 * this.hashArray.length); - } - - } - - static class Entry { - final long key; - V value; - LongHashMap.Entry nextEntry; - final int hash; - - Entry(int parInt1, long parLong1, V parObject, LongHashMap.Entry parEntry) { - this.value = parObject; - this.nextEntry = parEntry; - this.key = parLong1; - this.hash = parInt1; - } - - public final long getKey() { - return this.key; - } - - public final V getValue() { - return this.value; - } - - public final boolean equals(Object object) { - if (!(object instanceof LongHashMap.Entry)) { - return false; - } else { - LongHashMap.Entry longhashmap$entry = (LongHashMap.Entry) object; - Long olong = Long.valueOf(this.getKey()); - Long olong1 = Long.valueOf(longhashmap$entry.getKey()); - if (olong == olong1 || olong != null && olong.equals(olong1)) { - Object object1 = this.getValue(); - Object object2 = longhashmap$entry.getValue(); - if (object1 == object2 || object1 != null && object1.equals(object2)) { - return true; - } - } - - return false; - } - } - - public final int hashCode() { - return LongHashMap.getHashedKey(this.key); - } - - public final String toString() { - return this.getKey() + "=" + this.getValue(); - } - } -} \ No newline at end of file diff --git a/src/game/java/net/minecraft/util/MapPopulator.java b/src/game/java/net/minecraft/util/MapPopulator.java index 6803e8f0..1293f6ab 100755 --- a/src/game/java/net/minecraft/util/MapPopulator.java +++ b/src/game/java/net/minecraft/util/MapPopulator.java @@ -12,7 +12,7 @@ import com.google.common.collect.Maps; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/MathHelper.java b/src/game/java/net/minecraft/util/MathHelper.java index a3ec1c3f..c9c4fd1b 100755 --- a/src/game/java/net/minecraft/util/MathHelper.java +++ b/src/game/java/net/minecraft/util/MathHelper.java @@ -9,7 +9,7 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/Matrix4f.java b/src/game/java/net/minecraft/util/Matrix4f.java index 405202fb..339d9e5b 100755 --- a/src/game/java/net/minecraft/util/Matrix4f.java +++ b/src/game/java/net/minecraft/util/Matrix4f.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/MinecraftError.java b/src/game/java/net/minecraft/util/MinecraftError.java index 3d49afa8..f96d8013 100755 --- a/src/game/java/net/minecraft/util/MinecraftError.java +++ b/src/game/java/net/minecraft/util/MinecraftError.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/MouseFilter.java b/src/game/java/net/minecraft/util/MouseFilter.java index 28f1bd4b..64d6b8d8 100755 --- a/src/game/java/net/minecraft/util/MouseFilter.java +++ b/src/game/java/net/minecraft/util/MouseFilter.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/MouseHelper.java b/src/game/java/net/minecraft/util/MouseHelper.java index 100efb19..344b1254 100755 --- a/src/game/java/net/minecraft/util/MouseHelper.java +++ b/src/game/java/net/minecraft/util/MouseHelper.java @@ -10,7 +10,7 @@ import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/MovementInput.java b/src/game/java/net/minecraft/util/MovementInput.java index 08c83ae3..bcecc4c4 100755 --- a/src/game/java/net/minecraft/util/MovementInput.java +++ b/src/game/java/net/minecraft/util/MovementInput.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/MovementInputFromOptions.java b/src/game/java/net/minecraft/util/MovementInputFromOptions.java index 2b044060..02c40fd1 100755 --- a/src/game/java/net/minecraft/util/MovementInputFromOptions.java +++ b/src/game/java/net/minecraft/util/MovementInputFromOptions.java @@ -10,7 +10,7 @@ import net.minecraft.client.settings.GameSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/MovingObjectPosition.java b/src/game/java/net/minecraft/util/MovingObjectPosition.java index fac1f0bb..e39ddf37 100755 --- a/src/game/java/net/minecraft/util/MovingObjectPosition.java +++ b/src/game/java/net/minecraft/util/MovingObjectPosition.java @@ -8,7 +8,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/ObjectIntIdentityMap.java b/src/game/java/net/minecraft/util/ObjectIntIdentityMap.java index 6f025bc4..1c80bffb 100755 --- a/src/game/java/net/minecraft/util/ObjectIntIdentityMap.java +++ b/src/game/java/net/minecraft/util/ObjectIntIdentityMap.java @@ -1,9 +1,9 @@ package net.minecraft.util; -import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; +import com.carrotsearch.hppc.ObjectIntIdentityHashMap; import com.google.common.base.Predicates; import com.google.common.collect.Iterators; import com.google.common.collect.Lists; @@ -14,7 +14,7 @@ import com.google.common.collect.Lists; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -29,11 +29,11 @@ import com.google.common.collect.Lists; * */ public class ObjectIntIdentityMap implements IObjectIntIterable { - private final IdentityHashMap identityMap = new IdentityHashMap(512); + private final ObjectIntIdentityHashMap identityMap = new ObjectIntIdentityHashMap<>(512); private final List objectList = Lists.newArrayList(); public void put(T key, int value) { - this.identityMap.put(key, Integer.valueOf(value)); + this.identityMap.put(key, value); while (this.objectList.size() <= value) { this.objectList.add((T) null); @@ -43,8 +43,7 @@ public class ObjectIntIdentityMap implements IObjectIntIterable { } public int get(T key) { - Integer integer = (Integer) this.identityMap.get(key); - return integer == null ? -1 : integer.intValue(); + return this.identityMap.getOrDefault(key, -1); } public final T getByValue(int value) { diff --git a/src/game/java/net/minecraft/util/RegistryDefaulted.java b/src/game/java/net/minecraft/util/RegistryDefaulted.java index 120f8648..985b14f6 100755 --- a/src/game/java/net/minecraft/util/RegistryDefaulted.java +++ b/src/game/java/net/minecraft/util/RegistryDefaulted.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/RegistryNamespaced.java b/src/game/java/net/minecraft/util/RegistryNamespaced.java index 20387cc0..1bb5b93f 100755 --- a/src/game/java/net/minecraft/util/RegistryNamespaced.java +++ b/src/game/java/net/minecraft/util/RegistryNamespaced.java @@ -12,7 +12,7 @@ import com.google.common.collect.HashBiMap; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/RegistryNamespacedDefaultedByKey.java b/src/game/java/net/minecraft/util/RegistryNamespacedDefaultedByKey.java index 807a1a25..6bd61b4c 100755 --- a/src/game/java/net/minecraft/util/RegistryNamespacedDefaultedByKey.java +++ b/src/game/java/net/minecraft/util/RegistryNamespacedDefaultedByKey.java @@ -8,7 +8,7 @@ import org.apache.commons.lang3.Validate; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/RegistrySimple.java b/src/game/java/net/minecraft/util/RegistrySimple.java index ffc6eee4..55ec8f80 100755 --- a/src/game/java/net/minecraft/util/RegistrySimple.java +++ b/src/game/java/net/minecraft/util/RegistrySimple.java @@ -18,7 +18,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/ReportedException.java b/src/game/java/net/minecraft/util/ReportedException.java index 72282263..c4a79f54 100755 --- a/src/game/java/net/minecraft/util/ReportedException.java +++ b/src/game/java/net/minecraft/util/ReportedException.java @@ -8,7 +8,7 @@ import net.minecraft.crash.CrashReport; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/ResourceLocation.java b/src/game/java/net/minecraft/util/ResourceLocation.java index 95be5a8e..ce5c0eaf 100755 --- a/src/game/java/net/minecraft/util/ResourceLocation.java +++ b/src/game/java/net/minecraft/util/ResourceLocation.java @@ -8,7 +8,7 @@ import org.apache.commons.lang3.Validate; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/Rotations.java b/src/game/java/net/minecraft/util/Rotations.java index 7592fe39..b0c6e4f9 100755 --- a/src/game/java/net/minecraft/util/Rotations.java +++ b/src/game/java/net/minecraft/util/Rotations.java @@ -9,7 +9,7 @@ import net.minecraft.nbt.NBTTagList; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/ScreenShotHelper.java b/src/game/java/net/minecraft/util/ScreenShotHelper.java index b0e2192b..8ecf587b 100755 --- a/src/game/java/net/minecraft/util/ScreenShotHelper.java +++ b/src/game/java/net/minecraft/util/ScreenShotHelper.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.PlatformApplication; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/Session.java b/src/game/java/net/minecraft/util/Session.java index 97437379..25d0714c 100755 --- a/src/game/java/net/minecraft/util/Session.java +++ b/src/game/java/net/minecraft/util/Session.java @@ -12,7 +12,7 @@ import net.minecraft.entity.player.EntityPlayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/StatCollector.java b/src/game/java/net/minecraft/util/StatCollector.java index 80066a3a..7f486b9f 100755 --- a/src/game/java/net/minecraft/util/StatCollector.java +++ b/src/game/java/net/minecraft/util/StatCollector.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/StringTranslate.java b/src/game/java/net/minecraft/util/StringTranslate.java index ae34f3db..f7865e92 100755 --- a/src/game/java/net/minecraft/util/StringTranslate.java +++ b/src/game/java/net/minecraft/util/StringTranslate.java @@ -25,7 +25,7 @@ import java.util.regex.Pattern; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/StringUtils.java b/src/game/java/net/minecraft/util/StringUtils.java index cb02416b..0f0b3017 100755 --- a/src/game/java/net/minecraft/util/StringUtils.java +++ b/src/game/java/net/minecraft/util/StringUtils.java @@ -8,7 +8,7 @@ import java.util.regex.Pattern; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/Timer.java b/src/game/java/net/minecraft/util/Timer.java index 721001ec..0e40ca1b 100755 --- a/src/game/java/net/minecraft/util/Timer.java +++ b/src/game/java/net/minecraft/util/Timer.java @@ -9,7 +9,7 @@ import net.minecraft.client.Minecraft; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/Tuple.java b/src/game/java/net/minecraft/util/Tuple.java index 8255d615..f427d6ed 100755 --- a/src/game/java/net/minecraft/util/Tuple.java +++ b/src/game/java/net/minecraft/util/Tuple.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/TupleIntJsonSerializable.java b/src/game/java/net/minecraft/util/TupleIntJsonSerializable.java index db108384..9df39eb3 100755 --- a/src/game/java/net/minecraft/util/TupleIntJsonSerializable.java +++ b/src/game/java/net/minecraft/util/TupleIntJsonSerializable.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/Util.java b/src/game/java/net/minecraft/util/Util.java index 8c49abff..78a0d41b 100755 --- a/src/game/java/net/minecraft/util/Util.java +++ b/src/game/java/net/minecraft/util/Util.java @@ -11,7 +11,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/Vec3.java b/src/game/java/net/minecraft/util/Vec3.java index 0884af77..9d78e572 100755 --- a/src/game/java/net/minecraft/util/Vec3.java +++ b/src/game/java/net/minecraft/util/Vec3.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/Vec3i.java b/src/game/java/net/minecraft/util/Vec3i.java index e59af467..c4a18aa2 100755 --- a/src/game/java/net/minecraft/util/Vec3i.java +++ b/src/game/java/net/minecraft/util/Vec3i.java @@ -8,7 +8,7 @@ import com.google.common.base.Objects; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/Vec4b.java b/src/game/java/net/minecraft/util/Vec4b.java index 4ea4b0be..a9018d37 100755 --- a/src/game/java/net/minecraft/util/Vec4b.java +++ b/src/game/java/net/minecraft/util/Vec4b.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/Vector3d.java b/src/game/java/net/minecraft/util/Vector3d.java index 5ad69583..ba4dea9f 100755 --- a/src/game/java/net/minecraft/util/Vector3d.java +++ b/src/game/java/net/minecraft/util/Vector3d.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/WeightedRandom.java b/src/game/java/net/minecraft/util/WeightedRandom.java index 4a483c75..6b7a4e81 100755 --- a/src/game/java/net/minecraft/util/WeightedRandom.java +++ b/src/game/java/net/minecraft/util/WeightedRandom.java @@ -9,7 +9,7 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/WeightedRandomChestContent.java b/src/game/java/net/minecraft/util/WeightedRandomChestContent.java index f0157336..8a5c0a2b 100755 --- a/src/game/java/net/minecraft/util/WeightedRandomChestContent.java +++ b/src/game/java/net/minecraft/util/WeightedRandomChestContent.java @@ -18,7 +18,7 @@ import net.minecraft.tileentity.TileEntityDispenser; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/util/WeightedRandomFishable.java b/src/game/java/net/minecraft/util/WeightedRandomFishable.java index fbf8d066..f9233c12 100755 --- a/src/game/java/net/minecraft/util/WeightedRandomFishable.java +++ b/src/game/java/net/minecraft/util/WeightedRandomFishable.java @@ -11,7 +11,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/village/MerchantRecipe.java b/src/game/java/net/minecraft/village/MerchantRecipe.java index 632fe203..b0495161 100755 --- a/src/game/java/net/minecraft/village/MerchantRecipe.java +++ b/src/game/java/net/minecraft/village/MerchantRecipe.java @@ -10,7 +10,7 @@ import net.minecraft.nbt.NBTTagCompound; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/village/MerchantRecipeList.java b/src/game/java/net/minecraft/village/MerchantRecipeList.java index de043f27..b9d9cc46 100755 --- a/src/game/java/net/minecraft/village/MerchantRecipeList.java +++ b/src/game/java/net/minecraft/village/MerchantRecipeList.java @@ -15,7 +15,7 @@ import net.minecraft.network.PacketBuffer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/village/Village.java b/src/game/java/net/minecraft/village/Village.java index f1b2a993..19b244d1 100755 --- a/src/game/java/net/minecraft/village/Village.java +++ b/src/game/java/net/minecraft/village/Village.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -70,6 +70,28 @@ public class Village { this.worldObj = worldIn; } + private BlockPos[] positions = null; + + private void calculateNewCheckPositions() { + if (this.center == null || this.center.equals(BlockPos.ORIGIN)) { + this.positions = null; + } else { + this.positions = new BlockPos[] { this.center.add(-this.villageRadius, 0, -this.villageRadius), + this.center.add(-this.villageRadius, 0, this.villageRadius), + this.center.add(this.villageRadius, 0, -this.villageRadius), + this.center.add(this.villageRadius, 0, this.villageRadius), this.center }; + } + } + + public boolean isVillageAreaLoaded() { + for (int i = 0; this.positions != null && i < this.positions.length; i++) { + if (this.worldObj.isBlockLoaded(this.positions[i])) { + return true; + } + } + return false; + } + public void setWorld(World worldIn) { this.worldObj = worldIn; } @@ -78,6 +100,9 @@ public class Village { * Called periodically by VillageCollection */ public void tick(int parInt1) { + if (!isVillageAreaLoaded()) { + return; + } this.tickCounter = parInt1; this.removeDeadAndOutOfRangeDoors(); this.removeDeadAndOldAgressors(); @@ -379,6 +404,8 @@ public class Village { this.villageRadius = Math.max(32, (int) Math.sqrt((double) j) + 1); } + + calculateNewCheckPositions(); } /**+ @@ -443,6 +470,7 @@ public class Village { } } + calculateNewCheckPositions(); } /**+ diff --git a/src/game/java/net/minecraft/village/VillageCollection.java b/src/game/java/net/minecraft/village/VillageCollection.java index a1a4ffde..bfdea854 100755 --- a/src/game/java/net/minecraft/village/VillageCollection.java +++ b/src/game/java/net/minecraft/village/VillageCollection.java @@ -20,7 +20,7 @@ import net.minecraft.world.WorldSavedData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/village/VillageDoorInfo.java b/src/game/java/net/minecraft/village/VillageDoorInfo.java index 227e5591..3e4dc41f 100755 --- a/src/game/java/net/minecraft/village/VillageDoorInfo.java +++ b/src/game/java/net/minecraft/village/VillageDoorInfo.java @@ -9,7 +9,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/village/VillageSiege.java b/src/game/java/net/minecraft/village/VillageSiege.java index 2e2f24b7..a31742e1 100755 --- a/src/game/java/net/minecraft/village/VillageSiege.java +++ b/src/game/java/net/minecraft/village/VillageSiege.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/ChunkCache.java b/src/game/java/net/minecraft/world/ChunkCache.java index 5a63d5c3..59758d59 100755 --- a/src/game/java/net/minecraft/world/ChunkCache.java +++ b/src/game/java/net/minecraft/world/ChunkCache.java @@ -15,7 +15,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -104,6 +104,10 @@ public class ChunkCache implements IBlockAccess { return this.worldObj.getBiomeGenForCoords(blockpos); } + public int getBiomeColorForCoords(BlockPos var1, int index) { + return this.worldObj.getBiomeColorForCoords(var1, index); + } + private int getLightForExt(EnumSkyBlock pos, BlockPos parBlockPos) { if (pos == EnumSkyBlock.SKY && this.worldObj.provider.getHasNoSky()) { return Chunk.getNoSkyLightValue(); diff --git a/src/game/java/net/minecraft/world/ChunkCoordIntPair.java b/src/game/java/net/minecraft/world/ChunkCoordIntPair.java index e91a216d..93eac70e 100755 --- a/src/game/java/net/minecraft/world/ChunkCoordIntPair.java +++ b/src/game/java/net/minecraft/world/ChunkCoordIntPair.java @@ -8,7 +8,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/ColorizerFoliage.java b/src/game/java/net/minecraft/world/ColorizerFoliage.java index dd6f0a97..13f96a8a 100755 --- a/src/game/java/net/minecraft/world/ColorizerFoliage.java +++ b/src/game/java/net/minecraft/world/ColorizerFoliage.java @@ -6,7 +6,7 @@ package net.minecraft.world; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/ColorizerGrass.java b/src/game/java/net/minecraft/world/ColorizerGrass.java index 3b9d2683..3ec82cb6 100755 --- a/src/game/java/net/minecraft/world/ColorizerGrass.java +++ b/src/game/java/net/minecraft/world/ColorizerGrass.java @@ -6,7 +6,7 @@ package net.minecraft.world; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/DifficultyInstance.java b/src/game/java/net/minecraft/world/DifficultyInstance.java index 38abeb79..8d5d2788 100755 --- a/src/game/java/net/minecraft/world/DifficultyInstance.java +++ b/src/game/java/net/minecraft/world/DifficultyInstance.java @@ -8,7 +8,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/EnumDifficulty.java b/src/game/java/net/minecraft/world/EnumDifficulty.java index b228976e..5d9f68a8 100755 --- a/src/game/java/net/minecraft/world/EnumDifficulty.java +++ b/src/game/java/net/minecraft/world/EnumDifficulty.java @@ -6,7 +6,7 @@ package net.minecraft.world; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/EnumSkyBlock.java b/src/game/java/net/minecraft/world/EnumSkyBlock.java index 7ec4f164..bb95262d 100755 --- a/src/game/java/net/minecraft/world/EnumSkyBlock.java +++ b/src/game/java/net/minecraft/world/EnumSkyBlock.java @@ -6,7 +6,7 @@ package net.minecraft.world; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/Explosion.java b/src/game/java/net/minecraft/world/Explosion.java index 9322a866..a3659323 100755 --- a/src/game/java/net/minecraft/world/Explosion.java +++ b/src/game/java/net/minecraft/world/Explosion.java @@ -32,7 +32,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/GameRules.java b/src/game/java/net/minecraft/world/GameRules.java index cf5f9dab..9f195305 100755 --- a/src/game/java/net/minecraft/world/GameRules.java +++ b/src/game/java/net/minecraft/world/GameRules.java @@ -11,7 +11,7 @@ import net.minecraft.nbt.NBTTagCompound; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/IBlockAccess.java b/src/game/java/net/minecraft/world/IBlockAccess.java index 3adf278d..67add182 100755 --- a/src/game/java/net/minecraft/world/IBlockAccess.java +++ b/src/game/java/net/minecraft/world/IBlockAccess.java @@ -12,7 +12,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -43,6 +43,8 @@ public interface IBlockAccess { BiomeGenBase getBiomeGenForCoords(BlockPos var1); + int getBiomeColorForCoords(BlockPos var1, int index); + /**+ * set by !chunk.getAreLevelsEmpty */ diff --git a/src/game/java/net/minecraft/world/IInteractionObject.java b/src/game/java/net/minecraft/world/IInteractionObject.java index e1f0250c..3f4cfab8 100755 --- a/src/game/java/net/minecraft/world/IInteractionObject.java +++ b/src/game/java/net/minecraft/world/IInteractionObject.java @@ -10,7 +10,7 @@ import net.minecraft.inventory.Container; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/ILockableContainer.java b/src/game/java/net/minecraft/world/ILockableContainer.java index 051f62c4..222ca632 100755 --- a/src/game/java/net/minecraft/world/ILockableContainer.java +++ b/src/game/java/net/minecraft/world/ILockableContainer.java @@ -8,7 +8,7 @@ import net.minecraft.inventory.IInventory; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/IWorldAccess.java b/src/game/java/net/minecraft/world/IWorldAccess.java index 056e1cf8..c3bb1fc2 100755 --- a/src/game/java/net/minecraft/world/IWorldAccess.java +++ b/src/game/java/net/minecraft/world/IWorldAccess.java @@ -10,7 +10,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/IWorldNameable.java b/src/game/java/net/minecraft/world/IWorldNameable.java index e5e62b5b..027117b0 100755 --- a/src/game/java/net/minecraft/world/IWorldNameable.java +++ b/src/game/java/net/minecraft/world/IWorldNameable.java @@ -8,7 +8,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/LockCode.java b/src/game/java/net/minecraft/world/LockCode.java index c201f41a..17c18037 100755 --- a/src/game/java/net/minecraft/world/LockCode.java +++ b/src/game/java/net/minecraft/world/LockCode.java @@ -8,7 +8,7 @@ import net.minecraft.nbt.NBTTagCompound; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/NextTickListEntry.java b/src/game/java/net/minecraft/world/NextTickListEntry.java index b96ede2b..bda9bb3c 100755 --- a/src/game/java/net/minecraft/world/NextTickListEntry.java +++ b/src/game/java/net/minecraft/world/NextTickListEntry.java @@ -9,7 +9,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/SpawnerAnimals.java b/src/game/java/net/minecraft/world/SpawnerAnimals.java index 635e6f18..1625ec7e 100755 --- a/src/game/java/net/minecraft/world/SpawnerAnimals.java +++ b/src/game/java/net/minecraft/world/SpawnerAnimals.java @@ -1,12 +1,12 @@ package net.minecraft.world; -import com.google.common.collect.Sets; - +import com.carrotsearch.hppc.LongHashSet; +import com.carrotsearch.hppc.LongSet; +import com.carrotsearch.hppc.cursors.LongCursor; import java.util.List; import net.lax1dude.eaglercraft.v1_8.EagRuntime; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; -import java.util.Set; import net.minecraft.block.Block; import net.minecraft.entity.EntityList; import net.minecraft.entity.EntityLiving; @@ -27,7 +27,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -46,7 +46,7 @@ public final class SpawnerAnimals { /**+ * The 17x17 area around the player where mobs can spawn */ - private final Set eligibleChunksForSpawning = Sets.newHashSet(); + private final LongSet eligibleChunksForSpawning = new LongHashSet(); /**+ * adds all chunks within the spawn radius of the players to @@ -67,15 +67,16 @@ public final class SpawnerAnimals { if (!entityplayer.isSpectator()) { int j = MathHelper.floor_double(entityplayer.posX / 16.0D); int k = MathHelper.floor_double(entityplayer.posZ / 16.0D); - byte b0 = 8; + byte b0 = (byte) spawnHostileMobs.getMinecraftServer().getConfigurationManager().getViewDistance(); for (int l = -b0; l <= b0; ++l) { for (int i1 = -b0; i1 <= b0; ++i1) { boolean flag = l == -b0 || l == b0 || i1 == -b0 || i1 == b0; - ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(l + j, i1 + k); + int cx = l + j; + int cz = i1 + k; + long chunkcoordintpair = ChunkCoordIntPair.chunkXZ2Int(cx, cz); if (!this.eligibleChunksForSpawning.contains(chunkcoordintpair) - && spawnHostileMobs.theChunkProviderServer.chunkExists(chunkcoordintpair.chunkXPos, - chunkcoordintpair.chunkZPos)) { + && spawnHostileMobs.theChunkProviderServer.chunkExists(cx, cz)) { ++i; if (!flag && spawnHostileMobs.getWorldBorder().contains(chunkcoordintpair)) { this.eligibleChunksForSpawning.add(chunkcoordintpair); @@ -98,9 +99,11 @@ public final class SpawnerAnimals { int l3 = spawnHostileMobs.countEntities(enumcreaturetype.getCreatureClass()); int i4 = enumcreaturetype.getMaxNumberOfCreature() * i / MOB_COUNT_DIV; if (l3 <= i4) { - label374: for (ChunkCoordIntPair chunkcoordintpair1 : this.eligibleChunksForSpawning) { - BlockPos blockpos = getRandomChunkPosition(spawnHostileMobs, chunkcoordintpair1.chunkXPos, - chunkcoordintpair1.chunkZPos); + label374: for (LongCursor chunkcoordintpair1 : this.eligibleChunksForSpawning) { + long chunkcoordintpair1l = chunkcoordintpair1.value; + int chunkXPos = (int) (chunkcoordintpair1l & 4294967295L); + int chunkZPos = (int) (chunkcoordintpair1l >>> 32); + BlockPos blockpos = getRandomChunkPosition(spawnHostileMobs, chunkXPos, chunkZPos); int j1 = blockpos.getX(); int k1 = blockpos.getY(); int l1 = blockpos.getZ(); diff --git a/src/game/java/net/minecraft/world/Teleporter.java b/src/game/java/net/minecraft/world/Teleporter.java index 6e9b256d..6fc9a9c7 100755 --- a/src/game/java/net/minecraft/world/Teleporter.java +++ b/src/game/java/net/minecraft/world/Teleporter.java @@ -1,8 +1,9 @@ package net.minecraft.world; -import com.google.common.collect.Lists; -import java.util.Iterator; -import java.util.List; +import com.carrotsearch.hppc.LongArrayList; +import com.carrotsearch.hppc.LongObjectHashMap; +import com.carrotsearch.hppc.LongObjectMap; + import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; import net.minecraft.block.BlockPortal; import net.minecraft.block.state.IBlockState; @@ -11,7 +12,6 @@ import net.minecraft.entity.Entity; import net.minecraft.init.Blocks; import net.minecraft.util.BlockPos; import net.minecraft.util.EnumFacing; -import net.minecraft.util.LongHashMap; import net.minecraft.util.MathHelper; /**+ @@ -20,7 +20,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -41,12 +41,12 @@ public class Teleporter { * Stores successful portal placement locations for rapid * lookup. */ - private final LongHashMap destinationCoordinateCache = new LongHashMap(); + private final LongObjectMap destinationCoordinateCache = new LongObjectHashMap<>(); /**+ * A list of valid keys for the destinationCoordainteCache. * These are based on the X & Z of the players initial location. */ - private final List destinationCoordinateKeys = Lists.newArrayList(); + private final LongArrayList destinationCoordinateKeys = new LongArrayList(); public Teleporter(WorldServer worldIn) { this.worldServerInstance = worldIn; @@ -92,9 +92,8 @@ public class Teleporter { boolean flag1 = true; Object object = BlockPos.ORIGIN; long k = ChunkCoordIntPair.chunkXZ2Int(i, j); - if (this.destinationCoordinateCache.containsItem(k)) { - Teleporter.PortalPosition teleporter$portalposition = (Teleporter.PortalPosition) this.destinationCoordinateCache - .getValueByKey(k); + if (this.destinationCoordinateCache.containsKey(k)) { + Teleporter.PortalPosition teleporter$portalposition = this.destinationCoordinateCache.get(k); d0 = 0.0D; object = teleporter$portalposition; teleporter$portalposition.lastUpdateTime = this.worldServerInstance.getTotalWorldTime(); @@ -128,7 +127,7 @@ public class Teleporter { if (d0 >= 0.0D) { if (flag1) { - this.destinationCoordinateCache.add(k, + this.destinationCoordinateCache.put(k, new Teleporter.PortalPosition((BlockPos) object, this.worldServerInstance.getTotalWorldTime())); this.destinationCoordinateKeys.add(Long.valueOf(k)); } @@ -374,16 +373,14 @@ public class Teleporter { */ public void removeStalePortalLocations(long worldTime) { if (worldTime % 100L == 0L) { - Iterator iterator = this.destinationCoordinateKeys.iterator(); long i = worldTime - 300L; - while (iterator.hasNext()) { - Long olong = (Long) iterator.next(); - Teleporter.PortalPosition teleporter$portalposition = (Teleporter.PortalPosition) this.destinationCoordinateCache - .getValueByKey(olong.longValue()); + for (int j = 0; j < destinationCoordinateKeys.size(); ++j) { + long olong = destinationCoordinateKeys.get(j); + Teleporter.PortalPosition teleporter$portalposition = this.destinationCoordinateCache.get(olong); if (teleporter$portalposition == null || teleporter$portalposition.lastUpdateTime < i) { - iterator.remove(); - this.destinationCoordinateCache.remove(olong.longValue()); + destinationCoordinateKeys.removeAt(j--); + this.destinationCoordinateCache.remove(olong); } } } diff --git a/src/game/java/net/minecraft/world/World.java b/src/game/java/net/minecraft/world/World.java index adb5d6d0..ab3f7e5e 100755 --- a/src/game/java/net/minecraft/world/World.java +++ b/src/game/java/net/minecraft/world/World.java @@ -1,5 +1,9 @@ package net.minecraft.world; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; +import com.carrotsearch.hppc.LongHashSet; +import com.carrotsearch.hppc.LongSet; import com.google.common.base.Predicate; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -9,9 +13,9 @@ import java.util.Calendar; import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.Set; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; -import java.util.Set; import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; import net.lax1dude.eaglercraft.v1_8.HString; @@ -42,12 +46,12 @@ import net.minecraft.util.EntitySelectors; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.ITickable; -import net.minecraft.util.IntHashMap; import net.minecraft.util.MathHelper; import net.minecraft.util.MovingObjectPosition; import net.minecraft.util.ReportedException; import net.minecraft.util.Vec3; import net.minecraft.village.VillageCollection; +import net.minecraft.world.biome.BiomeColorHelper; import net.minecraft.world.biome.BiomeGenBase; import net.minecraft.world.biome.WorldChunkManager; import net.minecraft.world.border.WorldBorder; @@ -64,7 +68,7 @@ import net.minecraft.world.storage.WorldInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -89,8 +93,8 @@ public abstract class World implements IBlockAccess { /**+ * A list of the loaded tile entities in the world */ - public final List loadedTileEntityList = Lists.newArrayList(); - public final List tickableTileEntities = Lists.newArrayList(); + public final Set loadedTileEntityList = Sets.newIdentityHashSet(); + public final Set tickableTileEntities = Sets.newIdentityHashSet(); private final List addedTileEntityList = Lists.newArrayList(); private final List tileEntitiesToBeRemoved = Lists.newArrayList(); /**+ @@ -101,7 +105,7 @@ public abstract class World implements IBlockAccess { * a list of all the lightning entities */ public final List weatherEffects = Lists.newArrayList(); - protected final IntHashMap entitiesById = new IntHashMap(); + protected final IntObjectMap entitiesById = new IntObjectHashMap<>(); private long cloudColour = 16777215L; private int skylightSubtracted; /**+ @@ -138,7 +142,7 @@ public abstract class World implements IBlockAccess { /**+ * populated by chunks that are within 9 chunks of any player */ - protected Set activeChunkSet = Sets.newHashSet(); + protected LongSet activeChunkSet = new LongHashSet(); private int ambientTickCountdown; protected boolean spawnHostileMobs; protected boolean spawnPeacefulMobs; @@ -185,6 +189,10 @@ public abstract class World implements IBlockAccess { } } + public int getBiomeColorForCoords(BlockPos var1, int index) { + return BiomeColorHelper.getBiomeColorForCoordsOld(this, var1, index); + } + public WorldChunkManager getWorldChunkManager() { return this.provider.getWorldChunkManager(); } @@ -232,11 +240,11 @@ public abstract class World implements IBlockAccess { } public boolean isBlockLoaded(BlockPos pos) { - return this.isBlockLoaded(pos, true); + return !this.isValid(pos) ? false : this.isChunkLoaded(pos.x >> 4, pos.z >> 4, true); } public boolean isBlockLoaded(BlockPos pos, boolean allowEmpty) { - return !this.isValid(pos) ? false : this.isChunkLoaded(pos.getX() >> 4, pos.getZ() >> 4, allowEmpty); + return !this.isValid(pos) ? false : this.isChunkLoaded(pos.x >> 4, pos.z >> 4, allowEmpty); } public boolean isAreaLoaded(BlockPos center, int radius) { @@ -290,7 +298,13 @@ public abstract class World implements IBlockAccess { } public Chunk getChunkFromBlockCoords(BlockPos pos) { - return this.getChunkFromChunkCoords(pos.getX() >> 4, pos.getZ() >> 4); + return this.chunkProvider.provideChunk(pos.x >> 4, pos.z >> 4); + } + + public Chunk getChunkFromBlockCoordsIfLoaded(BlockPos pos) { + int x = pos.x >> 4; + int z = pos.z >> 4; + return this.chunkProvider.chunkExists(x, z) ? this.chunkProvider.provideChunk(x, z) : null; } /**+ @@ -301,6 +315,10 @@ public abstract class World implements IBlockAccess { return this.chunkProvider.provideChunk(chunkX, chunkZ); } + public Chunk getChunkFromChunkCoordsIfLoaded(int chunkX, int chunkZ) { + return this.chunkProvider.chunkExists(chunkX, chunkZ) ? this.chunkProvider.provideChunk(chunkX, chunkZ) : null; + } + /**+ * Convenience method to update the block on both the client and * server @@ -701,6 +719,15 @@ public abstract class World implements IBlockAccess { } } + public IBlockState getBlockStateIfLoaded(BlockPos pos) { + if (!this.isValid(pos)) { + return Blocks.air.getDefaultState(); + } else { + Chunk chunk = this.getChunkFromBlockCoordsIfLoaded(pos); + return chunk != null ? chunk.getBlockState(pos) : null; + } + } + /**+ * Checks whether its daytime by seeing if the light subtracted * from the skylight is less than 4 @@ -737,7 +764,9 @@ public abstract class World implements IBlockAccess { int i1 = MathHelper.floor_double(vec31.yCoord); int j1 = MathHelper.floor_double(vec31.zCoord); BlockPos blockpos = new BlockPos(l, i1, j1); - IBlockState iblockstate = this.getBlockState(blockpos); + IBlockState iblockstate = this.getBlockStateIfLoaded(blockpos); + if (iblockstate == null) + return null; Block block = iblockstate.getBlock(); if ((!ignoreBlockWithoutBoundingBox || block.getCollisionBoundingBox(this, blockpos, iblockstate) != null) @@ -836,7 +865,9 @@ public abstract class World implements IBlockAccess { i1 = MathHelper.floor_double(vec31.yCoord) - (enumfacing == EnumFacing.UP ? 1 : 0); j1 = MathHelper.floor_double(vec31.zCoord) - (enumfacing == EnumFacing.SOUTH ? 1 : 0); blockpos = new BlockPos(l, i1, j1); - IBlockState iblockstate1 = this.getBlockState(blockpos); + IBlockState iblockstate1 = this.getBlockStateIfLoaded(blockpos); + if (iblockstate1 == null) + return null; Block block1 = iblockstate1.getBlock(); if (!ignoreBlockWithoutBoundingBox || block1.getCollisionBoundingBox(this, blockpos, iblockstate1) != null) { @@ -2122,11 +2153,13 @@ public abstract class World implements IBlockAccess { EntityPlayer entityplayer = (EntityPlayer) this.playerEntities.get(i); int j = MathHelper.floor_double(entityplayer.posX / 16.0D); int k = MathHelper.floor_double(entityplayer.posZ / 16.0D); - int l = this.getRenderDistanceChunks(); + int l = this.getRenderDistanceChunks() - 1; + if (l < 1) + l = 1; for (int i1 = -l; i1 <= l; ++i1) { for (int j1 = -l; j1 <= l; ++j1) { - this.activeChunkSet.add(new ChunkCoordIntPair(i1 + j, j1 + k)); + this.activeChunkSet.add(ChunkCoordIntPair.chunkXZ2Int(i1 + j, j1 + k)); } } } @@ -2452,9 +2485,9 @@ public abstract class World implements IBlockAccess { for (int i1 = i; i1 <= j; ++i1) { for (int j1 = k; j1 <= l; ++j1) { - if (this.isChunkLoaded(i1, j1, true)) { - this.getChunkFromChunkCoords(i1, j1).getEntitiesWithinAABBForEntity(entityIn, boundingBox, - arraylist, predicate); + Chunk chunk = this.getChunkFromChunkCoordsIfLoaded(i1, j1); + if (chunk != null) { + chunk.getEntitiesWithinAABBForEntity(entityIn, boundingBox, arraylist, predicate); } } } @@ -2536,7 +2569,7 @@ public abstract class World implements IBlockAccess { * exist in this World. */ public Entity getEntityByID(int id) { - return (Entity) this.entitiesById.lookup(id); + return this.entitiesById.get(id); } /**+ diff --git a/src/game/java/net/minecraft/world/WorldManager.java b/src/game/java/net/minecraft/world/WorldManager.java index 490bb120..4b665fa0 100755 --- a/src/game/java/net/minecraft/world/WorldManager.java +++ b/src/game/java/net/minecraft/world/WorldManager.java @@ -15,7 +15,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/WorldProvider.java b/src/game/java/net/minecraft/world/WorldProvider.java index c4387c58..919bf6ca 100755 --- a/src/game/java/net/minecraft/world/WorldProvider.java +++ b/src/game/java/net/minecraft/world/WorldProvider.java @@ -20,7 +20,7 @@ import net.minecraft.world.gen.FlatGeneratorInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/WorldProviderEnd.java b/src/game/java/net/minecraft/world/WorldProviderEnd.java index c94ca0b1..9dfd7731 100755 --- a/src/game/java/net/minecraft/world/WorldProviderEnd.java +++ b/src/game/java/net/minecraft/world/WorldProviderEnd.java @@ -14,7 +14,7 @@ import net.minecraft.world.gen.ChunkProviderEnd; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/WorldProviderHell.java b/src/game/java/net/minecraft/world/WorldProviderHell.java index b1de94cf..5b1e8876 100755 --- a/src/game/java/net/minecraft/world/WorldProviderHell.java +++ b/src/game/java/net/minecraft/world/WorldProviderHell.java @@ -13,7 +13,7 @@ import net.minecraft.world.gen.ChunkProviderHell; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/WorldProviderSurface.java b/src/game/java/net/minecraft/world/WorldProviderSurface.java index a037c28b..e36e3256 100755 --- a/src/game/java/net/minecraft/world/WorldProviderSurface.java +++ b/src/game/java/net/minecraft/world/WorldProviderSurface.java @@ -6,7 +6,7 @@ package net.minecraft.world; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/WorldSavedData.java b/src/game/java/net/minecraft/world/WorldSavedData.java index 87007e50..edbab757 100755 --- a/src/game/java/net/minecraft/world/WorldSavedData.java +++ b/src/game/java/net/minecraft/world/WorldSavedData.java @@ -8,7 +8,7 @@ import net.minecraft.nbt.NBTTagCompound; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/WorldServer.java b/src/game/java/net/minecraft/world/WorldServer.java index 34381f42..d207d5a0 100755 --- a/src/game/java/net/minecraft/world/WorldServer.java +++ b/src/game/java/net/minecraft/world/WorldServer.java @@ -1,5 +1,6 @@ package net.minecraft.world; +import com.carrotsearch.hppc.cursors.LongCursor; import com.google.common.base.Predicate; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -75,7 +76,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -319,19 +320,22 @@ public class WorldServer extends World implements IThreadListener { protected void updateBlocks() { super.updateBlocks(); if (this.worldInfo.getTerrainType() == WorldType.DEBUG_WORLD) { - for (ChunkCoordIntPair chunkcoordintpair1 : this.activeChunkSet) { - this.getChunkFromChunkCoords(chunkcoordintpair1.chunkXPos, chunkcoordintpair1.chunkZPos) - .func_150804_b(false); + for (LongCursor chunkcoordintpair1 : this.activeChunkSet) { + long l = chunkcoordintpair1.value; + this.getChunkFromChunkCoords((int) (l & 4294967295L), (int) (l >>> 32)).func_150804_b(false); } } else { int i = 0; int j = 0; - for (ChunkCoordIntPair chunkcoordintpair : this.activeChunkSet) { - int k = chunkcoordintpair.chunkXPos * 16; - int l = chunkcoordintpair.chunkZPos * 16; - Chunk chunk = this.getChunkFromChunkCoords(chunkcoordintpair.chunkXPos, chunkcoordintpair.chunkZPos); + for (LongCursor chunkcoordintpair : this.activeChunkSet) { + long ll = chunkcoordintpair.value; + int chunkXPos = (int) (ll & 4294967295L); + int chunkZPos = (int) (ll >>> 32); + int k = chunkXPos * 16; + int l = chunkZPos * 16; + Chunk chunk = this.getChunkFromChunkCoords(chunkXPos, chunkZPos); this.playMoodSoundAndCheckLight(k, l, chunk); chunk.func_150804_b(false); if (this.rand.nextInt(100000) == 0 && this.isRaining() && this.isThundering()) { @@ -635,14 +639,22 @@ public class WorldServer extends World implements IThreadListener { * coordinates */ public List getTileEntitiesIn(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { - ArrayList arraylist = Lists.newArrayList(); + ArrayList arraylist = Lists.newArrayList(); - for (int i = 0; i < this.loadedTileEntityList.size(); ++i) { - TileEntity tileentity = (TileEntity) this.loadedTileEntityList.get(i); - BlockPos blockpos = tileentity.getPos(); - if (blockpos.getX() >= minX && blockpos.getY() >= minY && blockpos.getZ() >= minZ && blockpos.getX() < maxX - && blockpos.getY() < maxY && blockpos.getZ() < maxZ) { - arraylist.add(tileentity); + for (int chunkX = (minX >> 4); chunkX <= ((maxX - 1) >> 4); chunkX++) { + for (int chunkZ = (minZ >> 4); chunkZ <= ((maxZ - 1) >> 4); chunkZ++) { + Chunk chunk = getChunkFromChunkCoords(chunkX, chunkZ); + if (chunk == null) { + continue; + } + + for (TileEntity tileentity : chunk.getTileEntityMap().values()) { + BlockPos pos = tileentity.getPos(); + if ((pos.x >= minX) && (pos.y >= minY) && (pos.z >= minZ) && (pos.x < maxX) && (pos.y < maxY) + && (pos.z < maxZ)) { + arraylist.add(tileentity); + } + } } } @@ -819,12 +831,12 @@ public class WorldServer extends World implements IThreadListener { protected void onEntityAdded(Entity entity) { super.onEntityAdded(entity); - this.entitiesById.addKey(entity.getEntityId(), entity); + this.entitiesById.put(entity.getEntityId(), entity); this.entitiesByUuid.put(entity.getUniqueID(), entity); Entity[] aentity = entity.getParts(); if (aentity != null) { for (int i = 0; i < aentity.length; ++i) { - this.entitiesById.addKey(aentity[i].getEntityId(), aentity[i]); + this.entitiesById.put(aentity[i].getEntityId(), aentity[i]); } } @@ -832,12 +844,12 @@ public class WorldServer extends World implements IThreadListener { protected void onEntityRemoved(Entity entity) { super.onEntityRemoved(entity); - this.entitiesById.removeObject(entity.getEntityId()); + this.entitiesById.remove(entity.getEntityId()); this.entitiesByUuid.remove(entity.getUniqueID()); Entity[] aentity = entity.getParts(); if (aentity != null) { for (int i = 0; i < aentity.length; ++i) { - this.entitiesById.removeObject(aentity[i].getEntityId()); + this.entitiesById.remove(aentity[i].getEntityId()); } } diff --git a/src/game/java/net/minecraft/world/WorldServerMulti.java b/src/game/java/net/minecraft/world/WorldServerMulti.java index a7bb01c6..9732f64c 100755 --- a/src/game/java/net/minecraft/world/WorldServerMulti.java +++ b/src/game/java/net/minecraft/world/WorldServerMulti.java @@ -13,7 +13,7 @@ import net.minecraft.world.storage.ISaveHandler; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/WorldSettings.java b/src/game/java/net/minecraft/world/WorldSettings.java index 9f46d5f5..bd45ab7c 100755 --- a/src/game/java/net/minecraft/world/WorldSettings.java +++ b/src/game/java/net/minecraft/world/WorldSettings.java @@ -9,7 +9,7 @@ import net.minecraft.world.storage.WorldInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/WorldType.java b/src/game/java/net/minecraft/world/WorldType.java index 96efd5fd..ac0801f1 100755 --- a/src/game/java/net/minecraft/world/WorldType.java +++ b/src/game/java/net/minecraft/world/WorldType.java @@ -6,7 +6,7 @@ package net.minecraft.world; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeCache.java b/src/game/java/net/minecraft/world/biome/BiomeCache.java index c76f95c7..aaf48303 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeCache.java +++ b/src/game/java/net/minecraft/world/biome/BiomeCache.java @@ -1,9 +1,10 @@ package net.minecraft.world.biome; +import com.carrotsearch.hppc.LongObjectHashMap; +import com.carrotsearch.hppc.LongObjectMap; import com.google.common.collect.Lists; import java.util.List; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.LongHashMap; /**+ * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. @@ -11,7 +12,7 @@ import net.minecraft.util.LongHashMap; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -32,7 +33,7 @@ public class BiomeCache { * The map of keys to BiomeCacheBlocks. Keys are based on the * chunk x, z coordinates as (x | z << 32). */ - private LongHashMap cacheMap = new LongHashMap(); + private LongObjectMap cacheMap = new LongObjectHashMap<>(); /**+ * The list of cached BiomeCacheBlocks */ @@ -49,10 +50,10 @@ public class BiomeCache { x = x >> 4; z = z >> 4; long i = (long) x & 4294967295L | ((long) z & 4294967295L) << 32; - BiomeCache.Block biomecache$block = (BiomeCache.Block) this.cacheMap.getValueByKey(i); + BiomeCache.Block biomecache$block = this.cacheMap.get(i); if (biomecache$block == null) { biomecache$block = new BiomeCache.Block(x, z); - this.cacheMap.add(i, biomecache$block); + this.cacheMap.put(i, biomecache$block); this.cache.add(biomecache$block); } @@ -76,7 +77,7 @@ public class BiomeCache { this.lastCleanupTime = i; for (int k = 0; k < this.cache.size(); ++k) { - BiomeCache.Block biomecache$block = (BiomeCache.Block) this.cache.get(k); + BiomeCache.Block biomecache$block = this.cache.get(k); long l = i - biomecache$block.lastAccessTime; if (l > 30000L || l < 0L) { this.cache.remove(k--); diff --git a/src/game/java/net/minecraft/world/biome/BiomeColorHelper.java b/src/game/java/net/minecraft/world/biome/BiomeColorHelper.java index 98f3da1e..e78d6954 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeColorHelper.java +++ b/src/game/java/net/minecraft/world/biome/BiomeColorHelper.java @@ -9,7 +9,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -24,6 +24,7 @@ import net.minecraft.world.IBlockAccess; * */ public class BiomeColorHelper { + private static final BiomeColorHelper.ColorResolver field_180291_a = new BiomeColorHelper.ColorResolver() { public int getColorAtPos(BiomeGenBase blockPosition, BlockPos parBlockPos) { return blockPosition.getGrassColorAtPos(parBlockPos); @@ -59,15 +60,25 @@ public class BiomeColorHelper { } public static int getGrassColorAtPos(IBlockAccess parIBlockAccess, BlockPos parBlockPos) { - return func_180285_a(parIBlockAccess, parBlockPos, field_180291_a); + return parIBlockAccess.getBiomeColorForCoords(parBlockPos, 0); } public static int getFoliageColorAtPos(IBlockAccess parIBlockAccess, BlockPos parBlockPos) { - return func_180285_a(parIBlockAccess, parBlockPos, field_180289_b); + return parIBlockAccess.getBiomeColorForCoords(parBlockPos, 1); } public static int getWaterColorAtPos(IBlockAccess parIBlockAccess, BlockPos parBlockPos) { - return func_180285_a(parIBlockAccess, parBlockPos, field_180290_c); + return parIBlockAccess.getBiomeColorForCoords(parBlockPos, 2); + } + + public static int getBiomeColorForCoordsOld(IBlockAccess parIBlockAccess, BlockPos parBlockPos, int index) { + if (index == 0) { + return func_180285_a(parIBlockAccess, parBlockPos, field_180291_a); + } else if (index == 1) { + return func_180285_a(parIBlockAccess, parBlockPos, field_180289_b); + } else { + return func_180285_a(parIBlockAccess, parBlockPos, field_180290_c); + } } interface ColorResolver { diff --git a/src/game/java/net/minecraft/world/biome/BiomeDecorator.java b/src/game/java/net/minecraft/world/biome/BiomeDecorator.java index f0559d20..42e85489 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeDecorator.java +++ b/src/game/java/net/minecraft/world/biome/BiomeDecorator.java @@ -29,7 +29,7 @@ import net.minecraft.world.gen.feature.WorldGenerator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeEndDecorator.java b/src/game/java/net/minecraft/world/biome/BiomeEndDecorator.java index c59f376f..258cb27e 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeEndDecorator.java +++ b/src/game/java/net/minecraft/world/biome/BiomeEndDecorator.java @@ -11,7 +11,7 @@ import net.minecraft.world.gen.feature.WorldGenerator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenBase.java b/src/game/java/net/minecraft/world/biome/BiomeGenBase.java index 833a9aee..a615bebc 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenBase.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenBase.java @@ -55,7 +55,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenBeach.java b/src/game/java/net/minecraft/world/biome/BiomeGenBeach.java index 8522c1e7..de1a13df 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenBeach.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenBeach.java @@ -8,7 +8,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenDesert.java b/src/game/java/net/minecraft/world/biome/BiomeGenDesert.java index 5ec89e51..e9b9f9e3 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenDesert.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenDesert.java @@ -12,7 +12,7 @@ import net.minecraft.world.gen.feature.WorldGenDesertWells; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenEnd.java b/src/game/java/net/minecraft/world/biome/BiomeGenEnd.java index ab1ac3a8..feb29ccd 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenEnd.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenEnd.java @@ -9,7 +9,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenForest.java b/src/game/java/net/minecraft/world/biome/BiomeGenForest.java index b0e0e930..a1041520 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenForest.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenForest.java @@ -18,7 +18,7 @@ import net.minecraft.world.gen.feature.WorldGenForest; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenHell.java b/src/game/java/net/minecraft/world/biome/BiomeGenHell.java index d20356dc..6ebdd880 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenHell.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenHell.java @@ -10,7 +10,7 @@ import net.minecraft.entity.monster.EntityPigZombie; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenHills.java b/src/game/java/net/minecraft/world/biome/BiomeGenHills.java index d00be348..8eb3236a 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenHills.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenHills.java @@ -17,7 +17,7 @@ import net.minecraft.world.gen.feature.WorldGenerator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenJungle.java b/src/game/java/net/minecraft/world/biome/BiomeGenJungle.java index f11b4f7a..23b5f6fe 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenJungle.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenJungle.java @@ -27,7 +27,7 @@ import net.minecraft.world.gen.feature.WorldGenerator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenMesa.java b/src/game/java/net/minecraft/world/biome/BiomeGenMesa.java index bbc62066..4d4d342a 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenMesa.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenMesa.java @@ -21,7 +21,7 @@ import net.minecraft.world.gen.feature.WorldGenAbstractTree; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenMushroomIsland.java b/src/game/java/net/minecraft/world/biome/BiomeGenMushroomIsland.java index fdb2948d..08133b8b 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenMushroomIsland.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenMushroomIsland.java @@ -9,7 +9,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenMutated.java b/src/game/java/net/minecraft/world/biome/BiomeGenMutated.java index b28ec805..ede1c2fd 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenMutated.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenMutated.java @@ -15,7 +15,7 @@ import net.minecraft.world.gen.feature.WorldGenAbstractTree; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenOcean.java b/src/game/java/net/minecraft/world/biome/BiomeGenOcean.java index f79946e8..934bf461 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenOcean.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenOcean.java @@ -11,7 +11,7 @@ import net.minecraft.world.chunk.ChunkPrimer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenPlains.java b/src/game/java/net/minecraft/world/biome/BiomeGenPlains.java index 39ac214f..b23993a7 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenPlains.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenPlains.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenRiver.java b/src/game/java/net/minecraft/world/biome/BiomeGenRiver.java index c84304e5..be88812e 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenRiver.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenRiver.java @@ -6,7 +6,7 @@ package net.minecraft.world.biome; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenSavanna.java b/src/game/java/net/minecraft/world/biome/BiomeGenSavanna.java index b3710882..0628040d 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenSavanna.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenSavanna.java @@ -17,7 +17,7 @@ import net.minecraft.world.gen.feature.WorldGenSavannaTree; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenSnow.java b/src/game/java/net/minecraft/world/biome/BiomeGenSnow.java index cb00192b..08b114f2 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenSnow.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenSnow.java @@ -15,7 +15,7 @@ import net.minecraft.world.gen.feature.WorldGenTaiga2; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenStoneBeach.java b/src/game/java/net/minecraft/world/biome/BiomeGenStoneBeach.java index fc310bf7..fcfd09bd 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenStoneBeach.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenStoneBeach.java @@ -8,7 +8,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenSwamp.java b/src/game/java/net/minecraft/world/biome/BiomeGenSwamp.java index 81abc93a..80cd6d46 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenSwamp.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenSwamp.java @@ -16,7 +16,7 @@ import net.minecraft.world.gen.feature.WorldGenAbstractTree; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenTaiga.java b/src/game/java/net/minecraft/world/biome/BiomeGenTaiga.java index 25aa05f1..a14d2bb5 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenTaiga.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenTaiga.java @@ -23,7 +23,7 @@ import net.minecraft.world.gen.feature.WorldGenerator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/biome/WorldChunkManager.java b/src/game/java/net/minecraft/world/biome/WorldChunkManager.java index 09044925..b68c603c 100755 --- a/src/game/java/net/minecraft/world/biome/WorldChunkManager.java +++ b/src/game/java/net/minecraft/world/biome/WorldChunkManager.java @@ -18,7 +18,7 @@ import net.minecraft.world.gen.layer.IntCache; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -85,6 +85,13 @@ public class WorldChunkManager { return this.biomeCache.func_180284_a(pos.getX(), pos.getZ(), biomeGenBaseIn); } + /**+ + * Returns the biome generator + */ + public BiomeGenBase getBiomeGenerator(int x, int z, BiomeGenBase biomeGenBaseIn) { + return this.biomeCache.func_180284_a(x, z, biomeGenBaseIn); + } + /**+ * Returns a list of rainfall values for the specified blocks. * Args: listToReuse, x, z, width, length. diff --git a/src/game/java/net/minecraft/world/biome/WorldChunkManagerHell.java b/src/game/java/net/minecraft/world/biome/WorldChunkManagerHell.java index fe68f7ae..d968fa68 100755 --- a/src/game/java/net/minecraft/world/biome/WorldChunkManagerHell.java +++ b/src/game/java/net/minecraft/world/biome/WorldChunkManagerHell.java @@ -11,7 +11,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/border/EnumBorderStatus.java b/src/game/java/net/minecraft/world/border/EnumBorderStatus.java index 639c7438..150fcfaf 100755 --- a/src/game/java/net/minecraft/world/border/EnumBorderStatus.java +++ b/src/game/java/net/minecraft/world/border/EnumBorderStatus.java @@ -6,7 +6,7 @@ package net.minecraft.world.border; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/border/IBorderListener.java b/src/game/java/net/minecraft/world/border/IBorderListener.java index 854515f5..15239bee 100755 --- a/src/game/java/net/minecraft/world/border/IBorderListener.java +++ b/src/game/java/net/minecraft/world/border/IBorderListener.java @@ -6,7 +6,7 @@ package net.minecraft.world.border; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/border/WorldBorder.java b/src/game/java/net/minecraft/world/border/WorldBorder.java index d3608516..967e83eb 100755 --- a/src/game/java/net/minecraft/world/border/WorldBorder.java +++ b/src/game/java/net/minecraft/world/border/WorldBorder.java @@ -16,7 +16,7 @@ import net.minecraft.world.ChunkCoordIntPair; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -63,6 +63,13 @@ public class WorldBorder { && (double) range.getZEnd() > this.minZ() && (double) range.getZStart() < this.maxZ(); } + public boolean contains(long range) { + int chunkXPos = (int) (range & 4294967295L); + int chunkZPos = (int) (range >>> 32); + return (double) ((chunkXPos << 4) + 15) > this.minX() && (double) (chunkXPos << 4) < this.maxX() + && (double) ((chunkZPos << 4) + 15) > this.minZ() && (double) (chunkZPos << 4) < this.maxZ(); + } + public boolean contains(AxisAlignedBB bb) { return bb.maxX > this.minX() && bb.minX < this.maxX() && bb.maxZ > this.minZ() && bb.minZ < this.maxZ(); } diff --git a/src/game/java/net/minecraft/world/chunk/Chunk.java b/src/game/java/net/minecraft/world/chunk/Chunk.java index 48001678..97cd2d78 100755 --- a/src/game/java/net/minecraft/world/chunk/Chunk.java +++ b/src/game/java/net/minecraft/world/chunk/Chunk.java @@ -8,15 +8,11 @@ import java.util.List; import java.util.Map; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; -import java.util.concurrent.Callable; - import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer; import net.minecraft.block.Block; import net.minecraft.block.ITileEntityProvider; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; -import net.minecraft.crash.CrashReport; -import net.minecraft.crash.CrashReportCategory; import net.minecraft.entity.Entity; import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntity; @@ -25,7 +21,6 @@ import net.minecraft.util.BlockPos; import net.minecraft.util.ClassInheritanceMultiMap; import net.minecraft.util.EnumFacing; import net.minecraft.util.MathHelper; -import net.minecraft.util.ReportedException; import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.World; @@ -42,7 +37,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.DeferredStateManager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -80,6 +75,7 @@ public class Chunk { private long inhabitedTime; private int queuedLightChecks; private List tileEntityPosQueue; + private final ChunkCoordIntPair coordsCache; public Chunk(World worldIn, int x, int z) { this.storageArrays = new ExtendedBlockStorage[16]; @@ -94,6 +90,7 @@ public class Chunk { this.xPosition = x; this.zPosition = z; this.heightMap = new int[256]; + this.coordsCache = new ChunkCoordIntPair(x, z); for (int i = 0; i < this.entityLists.length; ++i) { this.entityLists[i] = new ClassInheritanceMultiMap(Entity.class); @@ -135,7 +132,7 @@ public class Chunk { } public int getHeight(BlockPos pos) { - return this.getHeightValue(pos.getX() & 15, pos.getZ() & 15); + return this.getHeightValue(pos.x & 15, pos.z & 15); } /**+ @@ -179,7 +176,7 @@ public class Chunk { this.precipitationHeightMap[j + (k << 4)] = -999; for (int l = i + 16; l > 0; --l) { - Block block = this.getBlock0(j, l - 1, k); + Block block = this.getBlock(j, l - 1, k); if (block.getLightOpacity() != 0) { this.heightMap[k << 4 | j] = l; if (l < this.heightMapMinimum) { @@ -422,112 +419,46 @@ public class Chunk { } private int getBlockLightOpacity(int x, int y, int z) { - return this.getBlock0(x, y, z).getLightOpacity(); + return this.getBlock(x, y, z).getLightOpacity(); } - /**+ - * Returns the block corresponding to the given coordinates - * inside a chunk. - */ - private Block getBlock0(int x, int y, int z) { - Block block = Blocks.air; + public Block getBlock(int x, int y, int z) { if (y >= 0 && y >> 4 < this.storageArrays.length) { ExtendedBlockStorage extendedblockstorage = this.storageArrays[y >> 4]; if (extendedblockstorage != null) { - try { - block = extendedblockstorage.getBlockByExtId(x, y & 15, z); - } catch (Throwable throwable) { - CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Getting block"); - throw new ReportedException(crashreport); - } + return extendedblockstorage.getBlockByExtId(x, y & 15, z); } } - return block; + return Blocks.air; } - public Block getBlock(final int x, final int y, final int z) { - try { - return this.getBlock0(x & 15, y, z & 15); - } catch (ReportedException reportedexception) { - CrashReportCategory crashreportcategory = reportedexception.getCrashReport() - .makeCategory("Block being got"); - crashreportcategory.addCrashSectionCallable("Location", new Callable() { - public String call() throws Exception { - return CrashReportCategory.getCoordinateInfo( - new BlockPos(Chunk.this.xPosition * 16 + x, y, Chunk.this.zPosition * 16 + z)); - } - }); - throw reportedexception; + public Block getBlock(final BlockPos pos) { + if (pos.y >= 0 && pos.y >> 4 < this.storageArrays.length) { + ExtendedBlockStorage extendedblockstorage = this.storageArrays[pos.y >> 4]; + if (extendedblockstorage != null) { + int j = pos.x & 15; + int k = pos.y & 15; + int i = pos.z & 15; + return extendedblockstorage.getBlockByExtId(j, k, i); + } } - } - public Block getBlock(final BlockPos blockpos) { - try { - return this.getBlock0(blockpos.getX() & 15, blockpos.getY(), blockpos.getZ() & 15); - } catch (ReportedException reportedexception) { - CrashReportCategory crashreportcategory = reportedexception.getCrashReport() - .makeCategory("Block being got"); - crashreportcategory.addCrashSectionCallable("Location", new Callable() { - public String call() throws Exception { - return CrashReportCategory.getCoordinateInfo(blockpos); - } - }); - throw reportedexception; - } + return Blocks.air; } public IBlockState getBlockState(final BlockPos pos) { - try { - if (pos.getY() >= 0 && pos.getY() >> 4 < this.storageArrays.length) { - ExtendedBlockStorage extendedblockstorage = this.storageArrays[pos.getY() >> 4]; - if (extendedblockstorage != null) { - int j = pos.getX() & 15; - int k = pos.getY() & 15; - int i = pos.getZ() & 15; - return extendedblockstorage.get(j, k, i); - } + if (pos.y >= 0 && pos.y >> 4 < this.storageArrays.length) { + ExtendedBlockStorage extendedblockstorage = this.storageArrays[pos.y >> 4]; + if (extendedblockstorage != null) { + int j = pos.x & 15; + int k = pos.y & 15; + int i = pos.z & 15; + return extendedblockstorage.get(j, k, i); } - - return Blocks.air.getDefaultState(); - } catch (Throwable throwable) { - CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Getting block state"); - CrashReportCategory crashreportcategory = crashreport.makeCategory("Block being got"); - crashreportcategory.addCrashSectionCallable("Location", new Callable() { - public String call() throws Exception { - return CrashReportCategory.getCoordinateInfo(pos); - } - }); - throw new ReportedException(crashreport); } - } - /** - * only use with a regular "net.minecraft.util.BlockPos"! - */ - public IBlockState getBlockStateFaster(final BlockPos pos) { - try { - if (pos.y >= 0 && pos.y >> 4 < this.storageArrays.length) { - ExtendedBlockStorage extendedblockstorage = this.storageArrays[pos.getY() >> 4]; - if (extendedblockstorage != null) { - int j = pos.x & 15; - int k = pos.y & 15; - int i = pos.z & 15; - return extendedblockstorage.get(j, k, i); - } - } - - return Blocks.air.getDefaultState(); - } catch (Throwable throwable) { - CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Getting block state"); - CrashReportCategory crashreportcategory = crashreport.makeCategory("Block being got"); - crashreportcategory.addCrashSectionCallable("Location", new Callable() { - public String call() throws Exception { - return CrashReportCategory.getCoordinateInfo(pos); - } - }); - throw new ReportedException(crashreport); - } + return Blocks.air.getDefaultState(); } /**+ @@ -552,9 +483,9 @@ public class Chunk { } public IBlockState setBlockState(BlockPos pos, IBlockState state) { - int i = pos.getX() & 15; - int j = pos.getY(); - int k = pos.getZ() & 15; + int i = pos.x & 15; + int j = pos.y; + int k = pos.z & 15; int l = k << 4 | i; if (j >= this.precipitationHeightMap[l] - 1) { this.precipitationHeightMap[l] = -999; @@ -641,9 +572,9 @@ public class Chunk { } public int getLightFor(EnumSkyBlock enumskyblock, BlockPos blockpos) { - int i = blockpos.getX() & 15; - int j = blockpos.getY(); - int k = blockpos.getZ() & 15; + int i = blockpos.x & 15; + int j = blockpos.y; + int k = blockpos.z & 15; ExtendedBlockStorage extendedblockstorage = this.storageArrays[j >> 4]; return extendedblockstorage == null ? (this.canSeeSky(blockpos) ? enumskyblock.defaultLightValue : getNoSkyLightValue()) @@ -655,9 +586,9 @@ public class Chunk { } public void setLightFor(EnumSkyBlock enumskyblock, BlockPos blockpos, int i) { - int j = blockpos.getX() & 15; - int k = blockpos.getY(); - int l = blockpos.getZ() & 15; + int j = blockpos.x & 15; + int k = blockpos.y; + int l = blockpos.z & 15; ExtendedBlockStorage extendedblockstorage = this.storageArrays[k >> 4]; if (extendedblockstorage == null) { extendedblockstorage = this.storageArrays[k >> 4] = new ExtendedBlockStorage(k >> 4 << 4, @@ -677,9 +608,9 @@ public class Chunk { } public int getLightSubtracted(BlockPos blockpos, int i) { - int j = blockpos.getX() & 15; - int k = blockpos.getY(); - int l = blockpos.getZ() & 15; + int j = blockpos.x & 15; + int k = blockpos.y; + int l = blockpos.z & 15; ExtendedBlockStorage extendedblockstorage = this.storageArrays[k >> 4]; if (extendedblockstorage == null) { return !this.worldObj.provider.getHasNoSky() && i < EnumSkyBlock.SKY.defaultLightValue @@ -754,9 +685,9 @@ public class Chunk { } public boolean canSeeSky(BlockPos blockpos) { - int i = blockpos.getX() & 15; - int j = blockpos.getY(); - int k = blockpos.getZ() & 15; + int i = blockpos.x & 15; + int j = blockpos.y; + int k = blockpos.z & 15; return j >= this.heightMap[k << 4 | i]; } @@ -1038,7 +969,11 @@ public class Chunk { * Gets a ChunkCoordIntPair representing the Chunk's position. */ public ChunkCoordIntPair getChunkCoordIntPair() { - return new ChunkCoordIntPair(this.xPosition, this.zPosition); + return coordsCache; + } + + public long getChunkCoordLong() { + return ChunkCoordIntPair.chunkXZ2Int(this.xPosition, this.zPosition); } /**+ diff --git a/src/game/java/net/minecraft/world/chunk/ChunkPrimer.java b/src/game/java/net/minecraft/world/chunk/ChunkPrimer.java index 2cd601c7..f3504c18 100755 --- a/src/game/java/net/minecraft/world/chunk/ChunkPrimer.java +++ b/src/game/java/net/minecraft/world/chunk/ChunkPrimer.java @@ -10,7 +10,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/chunk/EmptyChunk.java b/src/game/java/net/minecraft/world/chunk/EmptyChunk.java index 38240a1c..27789caa 100755 --- a/src/game/java/net/minecraft/world/chunk/EmptyChunk.java +++ b/src/game/java/net/minecraft/world/chunk/EmptyChunk.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/chunk/IChunkProvider.java b/src/game/java/net/minecraft/world/chunk/IChunkProvider.java index 12658c9d..c8996632 100755 --- a/src/game/java/net/minecraft/world/chunk/IChunkProvider.java +++ b/src/game/java/net/minecraft/world/chunk/IChunkProvider.java @@ -14,7 +14,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/chunk/NibbleArray.java b/src/game/java/net/minecraft/world/chunk/NibbleArray.java index ad7d4bf2..14f6436a 100755 --- a/src/game/java/net/minecraft/world/chunk/NibbleArray.java +++ b/src/game/java/net/minecraft/world/chunk/NibbleArray.java @@ -6,7 +6,7 @@ package net.minecraft.world.chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -55,18 +55,14 @@ public class NibbleArray { } public int getFromIndex(int index) { - int i = this.getNibbleIndex(index); - return this.isLowerNibble(index) ? this.data[i] & 15 : this.data[i] >> 4 & 15; + int shift = (index & 1) << 2; + return data[index >> 1] >> shift & 15; } public void setIndex(int index, int value) { - int i = this.getNibbleIndex(index); - if (this.isLowerNibble(index)) { - this.data[i] = (byte) (this.data[i] & 240 | value & 15); - } else { - this.data[i] = (byte) (this.data[i] & 15 | (value & 15) << 4); - } - + int i = index >> 1; + int shift = (index & 1) << 2; + data[i] = (byte) (data[i] & ~(15 << shift) | (value & 15) << shift); } private boolean isLowerNibble(int index) { diff --git a/src/game/java/net/minecraft/world/chunk/storage/AnvilChunkLoader.java b/src/game/java/net/minecraft/world/chunk/storage/AnvilChunkLoader.java index da9e46d1..76ddd377 100755 --- a/src/game/java/net/minecraft/world/chunk/storage/AnvilChunkLoader.java +++ b/src/game/java/net/minecraft/world/chunk/storage/AnvilChunkLoader.java @@ -22,7 +22,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/chunk/storage/ChunkLoader.java b/src/game/java/net/minecraft/world/chunk/storage/ChunkLoader.java index c0425e64..69e333d4 100755 --- a/src/game/java/net/minecraft/world/chunk/storage/ChunkLoader.java +++ b/src/game/java/net/minecraft/world/chunk/storage/ChunkLoader.java @@ -13,7 +13,7 @@ import net.minecraft.world.chunk.NibbleArray; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/chunk/storage/ExtendedBlockStorage.java b/src/game/java/net/minecraft/world/chunk/storage/ExtendedBlockStorage.java index 23a407af..591dece4 100755 --- a/src/game/java/net/minecraft/world/chunk/storage/ExtendedBlockStorage.java +++ b/src/game/java/net/minecraft/world/chunk/storage/ExtendedBlockStorage.java @@ -11,7 +11,7 @@ import net.minecraft.world.chunk.NibbleArray; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/chunk/storage/IChunkLoader.java b/src/game/java/net/minecraft/world/chunk/storage/IChunkLoader.java index 91d4512e..094c05a0 100755 --- a/src/game/java/net/minecraft/world/chunk/storage/IChunkLoader.java +++ b/src/game/java/net/minecraft/world/chunk/storage/IChunkLoader.java @@ -10,7 +10,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/chunk/storage/NibbleArrayReader.java b/src/game/java/net/minecraft/world/chunk/storage/NibbleArrayReader.java index f2b8d13f..f6f7f427 100755 --- a/src/game/java/net/minecraft/world/chunk/storage/NibbleArrayReader.java +++ b/src/game/java/net/minecraft/world/chunk/storage/NibbleArrayReader.java @@ -6,7 +6,7 @@ package net.minecraft.world.chunk.storage; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/chunk/storage/RegionFile.java b/src/game/java/net/minecraft/world/chunk/storage/RegionFile.java index 6fcfcbe4..92223e59 100755 --- a/src/game/java/net/minecraft/world/chunk/storage/RegionFile.java +++ b/src/game/java/net/minecraft/world/chunk/storage/RegionFile.java @@ -19,7 +19,7 @@ import net.lax1dude.eaglercraft.v1_8.sp.server.export.RandomAccessMemoryFile; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/demo/DemoWorldManager.java b/src/game/java/net/minecraft/world/demo/DemoWorldManager.java index d6e0825f..bbd60234 100755 --- a/src/game/java/net/minecraft/world/demo/DemoWorldManager.java +++ b/src/game/java/net/minecraft/world/demo/DemoWorldManager.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/demo/DemoWorldServer.java b/src/game/java/net/minecraft/world/demo/DemoWorldServer.java index 8f0d7bc8..55a22a3b 100755 --- a/src/game/java/net/minecraft/world/demo/DemoWorldServer.java +++ b/src/game/java/net/minecraft/world/demo/DemoWorldServer.java @@ -15,7 +15,7 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/ChunkProviderDebug.java b/src/game/java/net/minecraft/world/gen/ChunkProviderDebug.java index 941fed1f..9c5da316 100755 --- a/src/game/java/net/minecraft/world/gen/ChunkProviderDebug.java +++ b/src/game/java/net/minecraft/world/gen/ChunkProviderDebug.java @@ -21,7 +21,7 @@ import net.minecraft.world.chunk.IChunkProvider; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/ChunkProviderEnd.java b/src/game/java/net/minecraft/world/gen/ChunkProviderEnd.java index a6f4cebd..bbd6ed6b 100755 --- a/src/game/java/net/minecraft/world/gen/ChunkProviderEnd.java +++ b/src/game/java/net/minecraft/world/gen/ChunkProviderEnd.java @@ -22,7 +22,7 @@ import net.minecraft.world.chunk.IChunkProvider; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/ChunkProviderFlat.java b/src/game/java/net/minecraft/world/gen/ChunkProviderFlat.java index 78ae5159..4198ee95 100755 --- a/src/game/java/net/minecraft/world/gen/ChunkProviderFlat.java +++ b/src/game/java/net/minecraft/world/gen/ChunkProviderFlat.java @@ -30,7 +30,7 @@ import net.minecraft.world.gen.structure.StructureOceanMonument; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/ChunkProviderGenerate.java b/src/game/java/net/minecraft/world/gen/ChunkProviderGenerate.java index e3efc969..350fabb1 100755 --- a/src/game/java/net/minecraft/world/gen/ChunkProviderGenerate.java +++ b/src/game/java/net/minecraft/world/gen/ChunkProviderGenerate.java @@ -31,7 +31,7 @@ import net.minecraft.world.gen.structure.StructureOceanMonument; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/ChunkProviderHell.java b/src/game/java/net/minecraft/world/gen/ChunkProviderHell.java index 5fb958af..64309ec5 100755 --- a/src/game/java/net/minecraft/world/gen/ChunkProviderHell.java +++ b/src/game/java/net/minecraft/world/gen/ChunkProviderHell.java @@ -31,7 +31,7 @@ import net.minecraft.world.gen.structure.MapGenNetherBridge; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/ChunkProviderServer.java b/src/game/java/net/minecraft/world/gen/ChunkProviderServer.java index b0f95101..81c74345 100755 --- a/src/game/java/net/minecraft/world/gen/ChunkProviderServer.java +++ b/src/game/java/net/minecraft/world/gen/ChunkProviderServer.java @@ -1,19 +1,19 @@ package net.minecraft.world.gen; +import com.carrotsearch.hppc.LongHashSet; +import com.carrotsearch.hppc.LongObjectHashMap; +import com.carrotsearch.hppc.LongObjectMap; +import com.carrotsearch.hppc.LongSet; import com.google.common.collect.Lists; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import net.minecraft.crash.CrashReport; import net.minecraft.crash.CrashReportCategory; import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer; import net.minecraft.entity.EnumCreatureType; import net.minecraft.util.BlockPos; import net.minecraft.util.IProgressUpdate; -import net.minecraft.util.LongHashMap; import net.minecraft.util.ReportedException; import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.World; @@ -33,7 +33,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -49,7 +49,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; */ public class ChunkProviderServer implements IChunkProvider { private static final Logger logger = LogManager.getLogger(); - private Set droppedChunksSet = Collections.newSetFromMap(new ConcurrentHashMap()); + private LongSet droppedChunksSet = new LongHashSet(); private Chunk dummyChunk; private IChunkProvider serverChunkGenerator; private IChunkLoader chunkLoader; @@ -61,13 +61,13 @@ public class ChunkProviderServer implements IChunkProvider { /**+ * map of chunk Id's to Chunk instances */ - private LongHashMap id2ChunkMap = new LongHashMap(); + private LongObjectMap id2ChunkMap = new LongObjectHashMap<>(); private List loadedChunks = Lists.newLinkedList(); private WorldServer worldObj; public ChunkProviderServer(WorldServer parWorldServer, IChunkLoader parIChunkLoader, IChunkProvider parIChunkProvider) { - this.dummyChunk = new EmptyChunk(parWorldServer, 0, 0); + this.dummyChunk = new EmptyChunk(parWorldServer, Integer.MIN_VALUE, Integer.MIN_VALUE); this.worldObj = parWorldServer; this.chunkLoader = parIChunkLoader; this.serverChunkGenerator = parIChunkProvider; @@ -77,7 +77,7 @@ public class ChunkProviderServer implements IChunkProvider { * Checks to see if a chunk exists at x, z */ public boolean chunkExists(int i, int j) { - return this.id2ChunkMap.containsItem(ChunkCoordIntPair.chunkXZ2Int(i, j)); + return this.id2ChunkMap.containsKey(ChunkCoordIntPair.chunkXZ2Int(i, j)); } public List func_152380_a() { @@ -87,10 +87,10 @@ public class ChunkProviderServer implements IChunkProvider { public void dropChunk(int parInt1, int parInt2) { if (this.worldObj.provider.canRespawnHere()) { if (!this.worldObj.isSpawnChunk(parInt1, parInt2)) { - this.droppedChunksSet.add(Long.valueOf(ChunkCoordIntPair.chunkXZ2Int(parInt1, parInt2))); + this.droppedChunksSet.add(ChunkCoordIntPair.chunkXZ2Int(parInt1, parInt2)); } } else { - this.droppedChunksSet.add(Long.valueOf(ChunkCoordIntPair.chunkXZ2Int(parInt1, parInt2))); + this.droppedChunksSet.add(ChunkCoordIntPair.chunkXZ2Int(parInt1, parInt2)); } } @@ -110,8 +110,8 @@ public class ChunkProviderServer implements IChunkProvider { */ public Chunk loadChunk(int i, int j) { long k = ChunkCoordIntPair.chunkXZ2Int(i, j); - this.droppedChunksSet.remove(Long.valueOf(k)); - Chunk chunk = (Chunk) this.id2ChunkMap.getValueByKey(k); + this.droppedChunksSet.removeAll(k); + Chunk chunk = this.id2ChunkMap.get(k); if (chunk == null) { chunk = this.loadChunkFromFile(i, j); if (chunk == null) { @@ -136,7 +136,7 @@ public class ChunkProviderServer implements IChunkProvider { ++EaglerMinecraftServer.counterChunkRead; } - this.id2ChunkMap.add(k, chunk); + this.id2ChunkMap.put(k, chunk); this.loadedChunks.add(chunk); chunk.onChunkLoad(); chunk.populateChunk(this, this, i, j); @@ -151,7 +151,7 @@ public class ChunkProviderServer implements IChunkProvider { * chunk from the map seed and chunk seed */ public Chunk provideChunk(int i, int j) { - Chunk chunk = (Chunk) this.id2ChunkMap.getValueByKey(ChunkCoordIntPair.chunkXZ2Int(i, j)); + Chunk chunk = this.id2ChunkMap.get(ChunkCoordIntPair.chunkXZ2Int(i, j)); return chunk == null ? (!this.worldObj.isFindingSpawnPoint() && !this.chunkLoadOverride ? this.dummyChunk : this.loadChunk(i, j)) : chunk; } @@ -276,17 +276,17 @@ public class ChunkProviderServer implements IChunkProvider { if (!this.worldObj.disableLevelSaving) { for (int i = 0; i < 100; ++i) { if (!this.droppedChunksSet.isEmpty()) { - Long olong = (Long) this.droppedChunksSet.iterator().next(); - Chunk chunk = (Chunk) this.id2ChunkMap.getValueByKey(olong.longValue()); + long olong = this.droppedChunksSet.iterator().next().value; + Chunk chunk = this.id2ChunkMap.get(olong); if (chunk != null) { chunk.onChunkUnload(); this.saveChunkData(chunk); this.saveChunkExtraData(chunk); - this.id2ChunkMap.remove(olong.longValue()); + this.id2ChunkMap.remove(olong); this.loadedChunks.remove(chunk); } - this.droppedChunksSet.remove(olong); + this.droppedChunksSet.removeAll(olong); } } @@ -309,7 +309,7 @@ public class ChunkProviderServer implements IChunkProvider { * Converts the instance data to a readable string. */ public String makeString() { - return "ServerChunkCache: " + this.id2ChunkMap.getNumHashElements() + " Drop: " + this.droppedChunksSet.size(); + return "ServerChunkCache: " + this.id2ChunkMap.size() + " Drop: " + this.droppedChunksSet.size(); } public List getPossibleCreatures(EnumCreatureType enumcreaturetype, @@ -322,7 +322,7 @@ public class ChunkProviderServer implements IChunkProvider { } public int getLoadedChunkCount() { - return this.id2ChunkMap.getNumHashElements(); + return this.id2ChunkMap.size(); } public void recreateStructures(Chunk var1, int var2, int var3) { diff --git a/src/game/java/net/minecraft/world/gen/ChunkProviderSettings.java b/src/game/java/net/minecraft/world/gen/ChunkProviderSettings.java index 54405d70..04c5b5ff 100755 --- a/src/game/java/net/minecraft/world/gen/ChunkProviderSettings.java +++ b/src/game/java/net/minecraft/world/gen/ChunkProviderSettings.java @@ -13,7 +13,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/FlatGeneratorInfo.java b/src/game/java/net/minecraft/world/gen/FlatGeneratorInfo.java index 70b21653..bc7d1e46 100755 --- a/src/game/java/net/minecraft/world/gen/FlatGeneratorInfo.java +++ b/src/game/java/net/minecraft/world/gen/FlatGeneratorInfo.java @@ -21,7 +21,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/FlatLayerInfo.java b/src/game/java/net/minecraft/world/gen/FlatLayerInfo.java index 1c4480ab..5a2625d5 100755 --- a/src/game/java/net/minecraft/world/gen/FlatLayerInfo.java +++ b/src/game/java/net/minecraft/world/gen/FlatLayerInfo.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/GeneratorBushFeature.java b/src/game/java/net/minecraft/world/gen/GeneratorBushFeature.java index 666d8e75..04bd069b 100755 --- a/src/game/java/net/minecraft/world/gen/GeneratorBushFeature.java +++ b/src/game/java/net/minecraft/world/gen/GeneratorBushFeature.java @@ -12,7 +12,7 @@ import net.minecraft.world.gen.feature.WorldGenerator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/MapGenBase.java b/src/game/java/net/minecraft/world/gen/MapGenBase.java index e679535e..54eecf13 100755 --- a/src/game/java/net/minecraft/world/gen/MapGenBase.java +++ b/src/game/java/net/minecraft/world/gen/MapGenBase.java @@ -11,7 +11,7 @@ import net.minecraft.world.chunk.IChunkProvider; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/MapGenCaves.java b/src/game/java/net/minecraft/world/gen/MapGenCaves.java index ca518b16..ddd839dc 100755 --- a/src/game/java/net/minecraft/world/gen/MapGenCaves.java +++ b/src/game/java/net/minecraft/world/gen/MapGenCaves.java @@ -17,7 +17,7 @@ import net.minecraft.world.chunk.ChunkPrimer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/MapGenCavesHell.java b/src/game/java/net/minecraft/world/gen/MapGenCavesHell.java index b6f46f9b..8830812f 100755 --- a/src/game/java/net/minecraft/world/gen/MapGenCavesHell.java +++ b/src/game/java/net/minecraft/world/gen/MapGenCavesHell.java @@ -13,7 +13,7 @@ import net.minecraft.world.chunk.ChunkPrimer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/MapGenRavine.java b/src/game/java/net/minecraft/world/gen/MapGenRavine.java index 734a3e0d..da6ce462 100755 --- a/src/game/java/net/minecraft/world/gen/MapGenRavine.java +++ b/src/game/java/net/minecraft/world/gen/MapGenRavine.java @@ -14,7 +14,7 @@ import net.minecraft.world.chunk.ChunkPrimer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/NoiseGenerator.java b/src/game/java/net/minecraft/world/gen/NoiseGenerator.java index d438bf8d..4be4ad83 100755 --- a/src/game/java/net/minecraft/world/gen/NoiseGenerator.java +++ b/src/game/java/net/minecraft/world/gen/NoiseGenerator.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/NoiseGeneratorImproved.java b/src/game/java/net/minecraft/world/gen/NoiseGeneratorImproved.java index 23f2d407..ed2ad167 100755 --- a/src/game/java/net/minecraft/world/gen/NoiseGeneratorImproved.java +++ b/src/game/java/net/minecraft/world/gen/NoiseGeneratorImproved.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/NoiseGeneratorOctaves.java b/src/game/java/net/minecraft/world/gen/NoiseGeneratorOctaves.java index 7bdc242b..1917fce5 100755 --- a/src/game/java/net/minecraft/world/gen/NoiseGeneratorOctaves.java +++ b/src/game/java/net/minecraft/world/gen/NoiseGeneratorOctaves.java @@ -10,7 +10,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/NoiseGeneratorPerlin.java b/src/game/java/net/minecraft/world/gen/NoiseGeneratorPerlin.java index 61e52a4a..add8cf84 100755 --- a/src/game/java/net/minecraft/world/gen/NoiseGeneratorPerlin.java +++ b/src/game/java/net/minecraft/world/gen/NoiseGeneratorPerlin.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/NoiseGeneratorSimplex.java b/src/game/java/net/minecraft/world/gen/NoiseGeneratorSimplex.java index 06558833..1095db27 100755 --- a/src/game/java/net/minecraft/world/gen/NoiseGeneratorSimplex.java +++ b/src/game/java/net/minecraft/world/gen/NoiseGeneratorSimplex.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenAbstractTree.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenAbstractTree.java index dec881fb..c8ea53d6 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenAbstractTree.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenAbstractTree.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenBigMushroom.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenBigMushroom.java index d273980d..4140c864 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenBigMushroom.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenBigMushroom.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenBigTree.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenBigTree.java index 45ab3c4b..817027c1 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenBigTree.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenBigTree.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenBlockBlob.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenBlockBlob.java index 7ba4d736..067aa8f8 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenBlockBlob.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenBlockBlob.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenCactus.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenCactus.java index c4ef67af..27330ae1 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenCactus.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenCactus.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenCanopyTree.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenCanopyTree.java index c513608b..58bb36b8 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenCanopyTree.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenCanopyTree.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenClay.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenClay.java index 1309eaac..76c95e2b 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenClay.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenClay.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenDeadBush.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenDeadBush.java index 3d89e615..102de7f1 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenDeadBush.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenDeadBush.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenDesertWells.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenDesertWells.java index 062dd653..c489dd6c 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenDesertWells.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenDesertWells.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenDoublePlant.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenDoublePlant.java index 0d38a512..ead297e9 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenDoublePlant.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenDoublePlant.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenDungeons.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenDungeons.java index 79dc5951..68e488ce 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenDungeons.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenDungeons.java @@ -22,7 +22,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenFire.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenFire.java index 64a3e328..fa9263ed 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenFire.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenFire.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenFlowers.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenFlowers.java index 45512f27..a4991b2b 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenFlowers.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenFlowers.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenForest.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenForest.java index 0723d7d2..697a6aad 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenForest.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenForest.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenGlowStone1.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenGlowStone1.java index 7e049887..74b1bdc0 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenGlowStone1.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenGlowStone1.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenGlowStone2.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenGlowStone2.java index 017e5d79..e63676fe 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenGlowStone2.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenGlowStone2.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenHellLava.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenHellLava.java index 8b7041cb..e7c8d2e3 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenHellLava.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenHellLava.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenHugeTrees.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenHugeTrees.java index 092e7684..2f8b54af 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenHugeTrees.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenHugeTrees.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenIcePath.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenIcePath.java index deb6fce3..b180e6bd 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenIcePath.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenIcePath.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenIceSpike.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenIceSpike.java index e1695bf5..c9c0537c 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenIceSpike.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenIceSpike.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenLakes.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenLakes.java index 783b82fd..f8fe0123 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenLakes.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenLakes.java @@ -15,7 +15,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenLiquids.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenLiquids.java index 499987a3..7accf062 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenLiquids.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenLiquids.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenMegaJungle.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenMegaJungle.java index abe8f9c5..e4ea968e 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenMegaJungle.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenMegaJungle.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenMegaPineTree.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenMegaPineTree.java index 596d3ec1..d6fd7903 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenMegaPineTree.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenMegaPineTree.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenMelon.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenMelon.java index 09ba60b7..4585db25 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenMelon.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenMelon.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenMinable.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenMinable.java index 7947f97c..46e7a866 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenMinable.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenMinable.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenPumpkin.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenPumpkin.java index d54191a8..6be28ad4 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenPumpkin.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenPumpkin.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenReed.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenReed.java index 78d9c43c..9e471432 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenReed.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenReed.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenSand.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenSand.java index 3b473d8c..025498fd 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenSand.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenSand.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenSavannaTree.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenSavannaTree.java index 492087bf..6420fa26 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenSavannaTree.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenSavannaTree.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenShrub.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenShrub.java index a735b8fd..425d2e7d 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenShrub.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenShrub.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenSpikes.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenSpikes.java index 77aeacde..bbd8b06e 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenSpikes.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenSpikes.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenSwamp.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenSwamp.java index c1d56e1c..6197efbe 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenSwamp.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenSwamp.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenTaiga1.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenTaiga1.java index 64d37a14..e411affe 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenTaiga1.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenTaiga1.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenTaiga2.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenTaiga2.java index c8aaabe0..32832c0b 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenTaiga2.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenTaiga2.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenTallGrass.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenTallGrass.java index 8b382c75..285938fb 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenTallGrass.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenTallGrass.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenTrees.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenTrees.java index 859d696d..2c45a979 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenTrees.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenTrees.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenVines.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenVines.java index 5271b372..27fc982b 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenVines.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenVines.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenWaterlily.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenWaterlily.java index d7d3a3df..fb9728ca 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenWaterlily.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenWaterlily.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenerator.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenerator.java index e208a144..b97dfde2 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenerator.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenerator.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGeneratorBonusChest.java b/src/game/java/net/minecraft/world/gen/feature/WorldGeneratorBonusChest.java index 4cda84b3..8366b633 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGeneratorBonusChest.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGeneratorBonusChest.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayer.java b/src/game/java/net/minecraft/world/gen/layer/GenLayer.java index d8a92a5f..17581f12 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayer.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayer.java @@ -1,6 +1,8 @@ package net.minecraft.world.gen.layer; import java.util.concurrent.Callable; + +import net.lax1dude.eaglercraft.v1_8.sp.server.GenLayerEaglerRivers; import net.minecraft.crash.CrashReport; import net.minecraft.crash.CrashReportCategory; import net.minecraft.util.ReportedException; @@ -14,7 +16,7 @@ import net.minecraft.world.gen.ChunkProviderSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -29,7 +31,7 @@ import net.minecraft.world.gen.ChunkProviderSettings; * */ public abstract class GenLayer { - private long worldGenSeed; + protected long worldGenSeed; protected GenLayer parent; private long chunkSeed; protected long baseSeed; @@ -76,8 +78,9 @@ public abstract class GenLayer { GenLayer genlayerhills = new GenLayerHills(1000L, genlayerbiomeedge, genlayer1); GenLayer genlayer3 = GenLayerZoom.magnify(1000L, genlayerriverinit, 2); genlayer3 = GenLayerZoom.magnify(1000L, genlayer3, j); - GenLayerRiver genlayerriver = new GenLayerRiver(1L, genlayer3); - GenLayerSmooth genlayersmooth = new GenLayerSmooth(1000L, genlayerriver); + GenLayer genlayerriver = new GenLayerRiver(1L, genlayer3); + genlayerriver = new GenLayerSmooth(1000L, genlayerriver); + genlayerriver = new GenLayerEaglerRivers(69L, genlayerriver); genlayerhills = new GenLayerRareBiome(1001L, genlayerhills); for (int k = 0; k < i; ++k) { @@ -92,7 +95,7 @@ public abstract class GenLayer { } GenLayerSmooth genlayersmooth1 = new GenLayerSmooth(1000L, genlayerhills); - GenLayerRiverMix genlayerrivermix = new GenLayerRiverMix(100L, genlayersmooth1, genlayersmooth); + GenLayerRiverMix genlayerrivermix = new GenLayerRiverMix(100L, genlayersmooth1, genlayerriver); GenLayerVoronoiZoom genlayervoronoizoom = new GenLayerVoronoiZoom(10L, genlayerrivermix); genlayerrivermix.initWorldGenSeed(seed); genlayervoronoizoom.initWorldGenSeed(seed); diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerAddIsland.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerAddIsland.java index a2f8ae22..95266e84 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerAddIsland.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerAddIsland.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerAddMushroomIsland.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerAddMushroomIsland.java index e5b5e6fa..26086de0 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerAddMushroomIsland.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerAddMushroomIsland.java @@ -8,7 +8,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerAddSnow.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerAddSnow.java index 60db8b48..eb8d6828 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerAddSnow.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerAddSnow.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerBiome.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerBiome.java index bfa8bc50..29957780 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerBiome.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerBiome.java @@ -10,7 +10,7 @@ import net.minecraft.world.gen.ChunkProviderSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerBiomeEdge.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerBiomeEdge.java index 24f1701b..d357b3df 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerBiomeEdge.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerBiomeEdge.java @@ -8,7 +8,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerDeepOcean.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerDeepOcean.java index dabf0af3..ca196445 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerDeepOcean.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerDeepOcean.java @@ -8,7 +8,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerEdge.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerEdge.java index 928d51e2..7cd165e0 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerEdge.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerEdge.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerFuzzyZoom.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerFuzzyZoom.java index 2c52d911..10760ce8 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerFuzzyZoom.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerFuzzyZoom.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerHills.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerHills.java index eece564a..aa8a4234 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerHills.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerHills.java @@ -10,7 +10,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerIsland.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerIsland.java index 8477c75b..3e177e0c 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerIsland.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerIsland.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerRareBiome.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerRareBiome.java index 1bf70291..f28d030d 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerRareBiome.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerRareBiome.java @@ -8,7 +8,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerRemoveTooMuchOcean.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerRemoveTooMuchOcean.java index 2870d6b8..2ccec44d 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerRemoveTooMuchOcean.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerRemoveTooMuchOcean.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerRiver.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerRiver.java index 2e262c41..a83524e7 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerRiver.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerRiver.java @@ -8,7 +8,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerRiverInit.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerRiverInit.java index a7b466d8..81ef52b5 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerRiverInit.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerRiverInit.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerRiverMix.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerRiverMix.java index 5801f529..5cf4381a 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerRiverMix.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerRiverMix.java @@ -8,7 +8,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerShore.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerShore.java index a3363cc6..b4c9768e 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerShore.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerShore.java @@ -10,7 +10,7 @@ import net.minecraft.world.biome.BiomeGenMesa; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerSmooth.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerSmooth.java index afbd8b93..b538547c 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerSmooth.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerSmooth.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerVoronoiZoom.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerVoronoiZoom.java index e52bc819..95261989 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerVoronoiZoom.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerVoronoiZoom.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerZoom.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerZoom.java index bd7538e8..37ed52c1 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerZoom.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerZoom.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/layer/IntCache.java b/src/game/java/net/minecraft/world/gen/layer/IntCache.java index e17ed582..4d586011 100755 --- a/src/game/java/net/minecraft/world/gen/layer/IntCache.java +++ b/src/game/java/net/minecraft/world/gen/layer/IntCache.java @@ -9,7 +9,7 @@ import java.util.List; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/structure/ComponentScatteredFeaturePieces.java b/src/game/java/net/minecraft/world/gen/structure/ComponentScatteredFeaturePieces.java index 16be0f68..0cbb9a9f 100755 --- a/src/game/java/net/minecraft/world/gen/structure/ComponentScatteredFeaturePieces.java +++ b/src/game/java/net/minecraft/world/gen/structure/ComponentScatteredFeaturePieces.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/structure/MapGenMineshaft.java b/src/game/java/net/minecraft/world/gen/structure/MapGenMineshaft.java index b7592307..d6efd264 100755 --- a/src/game/java/net/minecraft/world/gen/structure/MapGenMineshaft.java +++ b/src/game/java/net/minecraft/world/gen/structure/MapGenMineshaft.java @@ -10,7 +10,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/structure/MapGenNetherBridge.java b/src/game/java/net/minecraft/world/gen/structure/MapGenNetherBridge.java index 35397246..e0d308f5 100755 --- a/src/game/java/net/minecraft/world/gen/structure/MapGenNetherBridge.java +++ b/src/game/java/net/minecraft/world/gen/structure/MapGenNetherBridge.java @@ -16,7 +16,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/structure/MapGenScatteredFeature.java b/src/game/java/net/minecraft/world/gen/structure/MapGenScatteredFeature.java index 059991ae..fb33e100 100755 --- a/src/game/java/net/minecraft/world/gen/structure/MapGenScatteredFeature.java +++ b/src/game/java/net/minecraft/world/gen/structure/MapGenScatteredFeature.java @@ -18,7 +18,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/structure/MapGenStronghold.java b/src/game/java/net/minecraft/world/gen/structure/MapGenStronghold.java index a2eb064b..b03d13f9 100755 --- a/src/game/java/net/minecraft/world/gen/structure/MapGenStronghold.java +++ b/src/game/java/net/minecraft/world/gen/structure/MapGenStronghold.java @@ -18,7 +18,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/structure/MapGenStructure.java b/src/game/java/net/minecraft/world/gen/structure/MapGenStructure.java index 0a61ee7d..3881f097 100755 --- a/src/game/java/net/minecraft/world/gen/structure/MapGenStructure.java +++ b/src/game/java/net/minecraft/world/gen/structure/MapGenStructure.java @@ -1,10 +1,11 @@ package net.minecraft.world.gen.structure; -import com.google.common.collect.Maps; +import com.carrotsearch.hppc.LongObjectHashMap; +import com.carrotsearch.hppc.LongObjectMap; +import com.carrotsearch.hppc.cursors.ObjectCursor; import java.util.Iterator; import java.util.List; -import java.util.Map; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; import net.lax1dude.eaglercraft.v1_8.HString; @@ -26,7 +27,7 @@ import net.minecraft.world.gen.MapGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -42,7 +43,13 @@ import net.minecraft.world.gen.MapGenBase; */ public abstract class MapGenStructure extends MapGenBase { private MapGenStructureData structureData; - protected Map structureMap = Maps.newHashMap(); + /**+ + * Used to store a list of all structures that have been + * recursively generated. Used so that during recursive + * generation, the structure generator can avoid generating + * structures that intersect ones that have already been placed. + */ + protected LongObjectMap structureMap = new LongObjectHashMap<>(); public abstract String getStructureName(); @@ -60,13 +67,13 @@ public abstract class MapGenStructure extends MapGenBase { protected final void recursiveGenerate(World world, final int i, final int j, int var4, int var5, ChunkPrimer var6) { this.func_143027_a(world); - if (!this.structureMap.containsKey(Long.valueOf(ChunkCoordIntPair.chunkXZ2Int(i, j)))) { + if (!this.structureMap.containsKey(ChunkCoordIntPair.chunkXZ2Int(i, j))) { this.rand.nextInt(); try { if (this.canSpawnStructureAtCoords(i, j)) { StructureStart structurestart = this.getStructureStart(i, j); - this.structureMap.put(Long.valueOf(ChunkCoordIntPair.chunkXZ2Int(i, j)), structurestart); + this.structureMap.put(ChunkCoordIntPair.chunkXZ2Int(i, j), structurestart); this.func_143026_a(i, j, structurestart); } @@ -102,7 +109,8 @@ public abstract class MapGenStructure extends MapGenBase { int j = (chunkCoord.chunkZPos << 4) + 8; boolean flag = false; - for (StructureStart structurestart : this.structureMap.values()) { + for (ObjectCursor structurestart_ : this.structureMap.values()) { + StructureStart structurestart = structurestart_.value; if (structurestart.isSizeableStructure() && structurestart.func_175788_a(chunkCoord) && structurestart.getBoundingBox().intersectsWith(i, j, i + 15, j + 15)) { structurestart.generateStructure(worldIn, randomIn, new StructureBoundingBox(i, j, i + 15, j + 15)); @@ -121,7 +129,8 @@ public abstract class MapGenStructure extends MapGenBase { } protected StructureStart func_175797_c(BlockPos pos) { - label24: for (StructureStart structurestart : this.structureMap.values()) { + label24: for (ObjectCursor structurestart_ : this.structureMap.values()) { + StructureStart structurestart = structurestart_.value; if (structurestart.isSizeableStructure() && structurestart.getBoundingBox().isVecInside(pos)) { Iterator iterator = structurestart.getComponents().iterator(); @@ -146,7 +155,8 @@ public abstract class MapGenStructure extends MapGenBase { public boolean func_175796_a(World worldIn, BlockPos pos) { this.func_143027_a(worldIn); - for (StructureStart structurestart : this.structureMap.values()) { + for (ObjectCursor structurestart_ : this.structureMap.values()) { + StructureStart structurestart = structurestart_.value; if (structurestart.isSizeableStructure() && structurestart.getBoundingBox().isVecInside(pos)) { return true; } @@ -168,7 +178,8 @@ public abstract class MapGenStructure extends MapGenBase { double d0 = Double.MAX_VALUE; BlockPos blockpos = null; - for (StructureStart structurestart : this.structureMap.values()) { + for (ObjectCursor structurestart_ : this.structureMap.values()) { + StructureStart structurestart = structurestart_.value; if (structurestart.isSizeableStructure()) { StructureComponent structurecomponent = (StructureComponent) structurestart.getComponents().get(0); BlockPos blockpos1 = structurecomponent.getBoundingBoxCenter(); @@ -232,8 +243,7 @@ public abstract class MapGenStructure extends MapGenBase { StructureStart structurestart = MapGenStructureIO.getStructureStart(nbttagcompound1, worldIn); if (structurestart != null) { - this.structureMap.put(Long.valueOf(ChunkCoordIntPair.chunkXZ2Int(i, j)), - structurestart); + this.structureMap.put(ChunkCoordIntPair.chunkXZ2Int(i, j), structurestart); } } } diff --git a/src/game/java/net/minecraft/world/gen/structure/MapGenStructureData.java b/src/game/java/net/minecraft/world/gen/structure/MapGenStructureData.java index 07e3b0c0..7a9205ff 100755 --- a/src/game/java/net/minecraft/world/gen/structure/MapGenStructureData.java +++ b/src/game/java/net/minecraft/world/gen/structure/MapGenStructureData.java @@ -9,7 +9,7 @@ import net.minecraft.world.WorldSavedData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/structure/MapGenStructureIO.java b/src/game/java/net/minecraft/world/gen/structure/MapGenStructureIO.java index 12659c5f..5942ec41 100755 --- a/src/game/java/net/minecraft/world/gen/structure/MapGenStructureIO.java +++ b/src/game/java/net/minecraft/world/gen/structure/MapGenStructureIO.java @@ -15,7 +15,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/structure/MapGenVillage.java b/src/game/java/net/minecraft/world/gen/structure/MapGenVillage.java index a9b07f01..fe394887 100755 --- a/src/game/java/net/minecraft/world/gen/structure/MapGenVillage.java +++ b/src/game/java/net/minecraft/world/gen/structure/MapGenVillage.java @@ -16,7 +16,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureBoundingBox.java b/src/game/java/net/minecraft/world/gen/structure/StructureBoundingBox.java index eb14fc20..77bb79a3 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureBoundingBox.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureBoundingBox.java @@ -12,7 +12,7 @@ import net.minecraft.util.Vec3i; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureComponent.java b/src/game/java/net/minecraft/world/gen/structure/StructureComponent.java index 325d5030..9cf6f40b 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureComponent.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureComponent.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureMineshaftPieces.java b/src/game/java/net/minecraft/world/gen/structure/StructureMineshaftPieces.java index 24464acf..0dbf62b7 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureMineshaftPieces.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureMineshaftPieces.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureMineshaftStart.java b/src/game/java/net/minecraft/world/gen/structure/StructureMineshaftStart.java index 13fcb8a0..c8392664 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureMineshaftStart.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureMineshaftStart.java @@ -9,7 +9,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureNetherBridgePieces.java b/src/game/java/net/minecraft/world/gen/structure/StructureNetherBridgePieces.java index 28767af6..8399ffd3 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureNetherBridgePieces.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureNetherBridgePieces.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureOceanMonument.java b/src/game/java/net/minecraft/world/gen/structure/StructureOceanMonument.java index 9f93fb34..cc2eb8d8 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureOceanMonument.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureOceanMonument.java @@ -24,7 +24,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureOceanMonumentPieces.java b/src/game/java/net/minecraft/world/gen/structure/StructureOceanMonumentPieces.java index 87807c63..e4e4fbd3 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureOceanMonumentPieces.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureOceanMonumentPieces.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureStart.java b/src/game/java/net/minecraft/world/gen/structure/StructureStart.java index fedaef13..0ff00970 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureStart.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureStart.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureStrongholdPieces.java b/src/game/java/net/minecraft/world/gen/structure/StructureStrongholdPieces.java index 5cb75ce8..03acba33 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureStrongholdPieces.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureStrongholdPieces.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureVillagePieces.java b/src/game/java/net/minecraft/world/gen/structure/StructureVillagePieces.java index cdce5674..327c8c4b 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureVillagePieces.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureVillagePieces.java @@ -32,7 +32,7 @@ import net.minecraft.world.biome.WorldChunkManager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/pathfinder/NodeProcessor.java b/src/game/java/net/minecraft/world/pathfinder/NodeProcessor.java index 9b595c9c..55bf429d 100755 --- a/src/game/java/net/minecraft/world/pathfinder/NodeProcessor.java +++ b/src/game/java/net/minecraft/world/pathfinder/NodeProcessor.java @@ -1,8 +1,10 @@ package net.minecraft.world.pathfinder; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; + import net.minecraft.entity.Entity; import net.minecraft.pathfinding.PathPoint; -import net.minecraft.util.IntHashMap; import net.minecraft.util.MathHelper; import net.minecraft.world.IBlockAccess; @@ -12,7 +14,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -28,14 +30,14 @@ import net.minecraft.world.IBlockAccess; */ public abstract class NodeProcessor { protected IBlockAccess blockaccess; - protected IntHashMap pointMap = new IntHashMap(); + protected IntObjectMap pointMap = new IntObjectHashMap<>(); protected int entitySizeX; protected int entitySizeY; protected int entitySizeZ; public void initProcessor(IBlockAccess iblockaccessIn, Entity entityIn) { this.blockaccess = iblockaccessIn; - this.pointMap.clearMap(); + this.pointMap.clear(); this.entitySizeX = MathHelper.floor_float(entityIn.width + 1.0F); this.entitySizeY = MathHelper.floor_float(entityIn.height + 1.0F); this.entitySizeZ = MathHelper.floor_float(entityIn.width + 1.0F); @@ -57,10 +59,10 @@ public abstract class NodeProcessor { */ protected PathPoint openPoint(int x, int y, int z) { int i = PathPoint.makeHash(x, y, z); - PathPoint pathpoint = (PathPoint) this.pointMap.lookup(i); + PathPoint pathpoint = this.pointMap.get(i); if (pathpoint == null) { pathpoint = new PathPoint(x, y, z); - this.pointMap.addKey(i, pathpoint); + this.pointMap.put(i, pathpoint); } return pathpoint; diff --git a/src/game/java/net/minecraft/world/pathfinder/SwimNodeProcessor.java b/src/game/java/net/minecraft/world/pathfinder/SwimNodeProcessor.java index 913f9c77..03811bdf 100755 --- a/src/game/java/net/minecraft/world/pathfinder/SwimNodeProcessor.java +++ b/src/game/java/net/minecraft/world/pathfinder/SwimNodeProcessor.java @@ -15,7 +15,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/pathfinder/WalkNodeProcessor.java b/src/game/java/net/minecraft/world/pathfinder/WalkNodeProcessor.java index d8844366..d546e9e2 100755 --- a/src/game/java/net/minecraft/world/pathfinder/WalkNodeProcessor.java +++ b/src/game/java/net/minecraft/world/pathfinder/WalkNodeProcessor.java @@ -20,7 +20,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/storage/DerivedWorldInfo.java b/src/game/java/net/minecraft/world/storage/DerivedWorldInfo.java index 24e50ae1..9359d1fd 100755 --- a/src/game/java/net/minecraft/world/storage/DerivedWorldInfo.java +++ b/src/game/java/net/minecraft/world/storage/DerivedWorldInfo.java @@ -13,7 +13,7 @@ import net.minecraft.world.WorldType; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/storage/IPlayerFileData.java b/src/game/java/net/minecraft/world/storage/IPlayerFileData.java index 2524c797..fc5addff 100755 --- a/src/game/java/net/minecraft/world/storage/IPlayerFileData.java +++ b/src/game/java/net/minecraft/world/storage/IPlayerFileData.java @@ -9,7 +9,7 @@ import net.minecraft.nbt.NBTTagCompound; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/storage/ISaveFormat.java b/src/game/java/net/minecraft/world/storage/ISaveFormat.java index b0fff086..73669896 100755 --- a/src/game/java/net/minecraft/world/storage/ISaveFormat.java +++ b/src/game/java/net/minecraft/world/storage/ISaveFormat.java @@ -9,7 +9,7 @@ import net.minecraft.util.IProgressUpdate; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/storage/ISaveHandler.java b/src/game/java/net/minecraft/world/storage/ISaveHandler.java index 75d5711a..de7f8f62 100755 --- a/src/game/java/net/minecraft/world/storage/ISaveHandler.java +++ b/src/game/java/net/minecraft/world/storage/ISaveHandler.java @@ -11,7 +11,7 @@ import net.minecraft.world.chunk.storage.IChunkLoader; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/storage/MapData.java b/src/game/java/net/minecraft/world/storage/MapData.java index 8d82a623..1816043f 100755 --- a/src/game/java/net/minecraft/world/storage/MapData.java +++ b/src/game/java/net/minecraft/world/storage/MapData.java @@ -25,7 +25,7 @@ import net.minecraft.world.WorldSavedData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/storage/MapStorage.java b/src/game/java/net/minecraft/world/storage/MapStorage.java index 0e9cf019..33c4597f 100755 --- a/src/game/java/net/minecraft/world/storage/MapStorage.java +++ b/src/game/java/net/minecraft/world/storage/MapStorage.java @@ -27,7 +27,7 @@ import net.minecraft.world.gen.structure.MapGenStructureData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/storage/SaveDataMemoryStorage.java b/src/game/java/net/minecraft/world/storage/SaveDataMemoryStorage.java index 78e8b55e..57c7a794 100755 --- a/src/game/java/net/minecraft/world/storage/SaveDataMemoryStorage.java +++ b/src/game/java/net/minecraft/world/storage/SaveDataMemoryStorage.java @@ -8,7 +8,7 @@ import net.minecraft.world.WorldSavedData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/storage/SaveFormatComparator.java b/src/game/java/net/minecraft/world/storage/SaveFormatComparator.java index ace4cbbc..9bbb152a 100755 --- a/src/game/java/net/minecraft/world/storage/SaveFormatComparator.java +++ b/src/game/java/net/minecraft/world/storage/SaveFormatComparator.java @@ -9,7 +9,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/storage/SaveFormatOld.java b/src/game/java/net/minecraft/world/storage/SaveFormatOld.java index 24739d32..b01f4cb3 100755 --- a/src/game/java/net/minecraft/world/storage/SaveFormatOld.java +++ b/src/game/java/net/minecraft/world/storage/SaveFormatOld.java @@ -22,7 +22,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/storage/SaveHandler.java b/src/game/java/net/minecraft/world/storage/SaveHandler.java index 84bbcc2f..8db99dc3 100755 --- a/src/game/java/net/minecraft/world/storage/SaveHandler.java +++ b/src/game/java/net/minecraft/world/storage/SaveHandler.java @@ -21,7 +21,7 @@ import net.lax1dude.eaglercraft.v1_8.sp.server.WorldsDB; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/storage/SaveHandlerMP.java b/src/game/java/net/minecraft/world/storage/SaveHandlerMP.java index 3a5e2da4..2d2a2c85 100755 --- a/src/game/java/net/minecraft/world/storage/SaveHandlerMP.java +++ b/src/game/java/net/minecraft/world/storage/SaveHandlerMP.java @@ -11,7 +11,7 @@ import net.minecraft.world.chunk.storage.IChunkLoader; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/game/java/net/minecraft/world/storage/WorldInfo.java b/src/game/java/net/minecraft/world/storage/WorldInfo.java index 69e5ad65..2fd64fcd 100755 --- a/src/game/java/net/minecraft/world/storage/WorldInfo.java +++ b/src/game/java/net/minecraft/world/storage/WorldInfo.java @@ -17,7 +17,7 @@ import net.lax1dude.eaglercraft.v1_8.HString; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java index 7fbabe91..cf074821 100755 --- a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java +++ b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java @@ -18,9 +18,12 @@ import java.util.Date; import java.util.List; import java.util.Random; import java.util.function.Consumer; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; +import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; import javax.imageio.ImageIO; @@ -556,6 +559,16 @@ public class PlatformRuntime { return new DeflaterOutputStream(os); } + public static int deflateFull(byte[] input, int inputOff, int inputLen, byte[] output, int outputOff, + int outputLen) throws IOException { + Deflater df = new Deflater(); + df.setInput(input, inputOff, inputLen); + df.finish(); + int i = df.deflate(output, outputOff, outputLen); + df.end(); + return i; + } + public static OutputStream newGZIPOutputStream(OutputStream os) throws IOException { return new GZIPOutputStream(os); } @@ -564,6 +577,21 @@ public class PlatformRuntime { return new InflaterInputStream(is); } + public static int inflateFull(byte[] input, int inputOff, int inputLen, byte[] output, int outputOff, + int outputLen) throws IOException { + Inflater df = new Inflater(); + int i; + try { + df.setInput(input, inputOff, inputLen); + i = df.inflate(output, outputOff, outputLen); + }catch(DataFormatException ex) { + throw new IOException("Failed to inflate!", ex); + }finally { + df.end(); + } + return i; + } + public static InputStream newGZIPInputStream(InputStream is) throws IOException { return new GZIPInputStream(is); } diff --git a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLByteBuffer.java b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLByteBuffer.java index 4d2a0877..ff1cf320 100755 --- a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLByteBuffer.java +++ b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLByteBuffer.java @@ -4,7 +4,7 @@ import net.lax1dude.unsafememcpy.UnsafeMemcpy; import net.lax1dude.unsafememcpy.UnsafeUtils; /** - * Copyright (c) 2022-2024 lax1dude. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -18,7 +18,7 @@ import net.lax1dude.unsafememcpy.UnsafeUtils; * POSSIBILITY OF SUCH DAMAGE. * */ -public class EaglerLWJGLByteBuffer implements ByteBuffer { +public class EaglerLWJGLByteBuffer extends ByteBuffer { final long address; final boolean original; diff --git a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLFloatBuffer.java b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLFloatBuffer.java index 55fcf8a3..f839dbfb 100755 --- a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLFloatBuffer.java +++ b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLFloatBuffer.java @@ -4,7 +4,7 @@ import net.lax1dude.unsafememcpy.UnsafeMemcpy; import net.lax1dude.unsafememcpy.UnsafeUtils; /** - * Copyright (c) 2022-2024 lax1dude. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -18,7 +18,7 @@ import net.lax1dude.unsafememcpy.UnsafeUtils; * POSSIBILITY OF SUCH DAMAGE. * */ -public class EaglerLWJGLFloatBuffer implements FloatBuffer { +public class EaglerLWJGLFloatBuffer extends FloatBuffer { final long address; final boolean original; diff --git a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLIntBuffer.java b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLIntBuffer.java index c52534fa..392f7a17 100755 --- a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLIntBuffer.java +++ b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLIntBuffer.java @@ -4,7 +4,7 @@ import net.lax1dude.unsafememcpy.UnsafeMemcpy; import net.lax1dude.unsafememcpy.UnsafeUtils; /** - * Copyright (c) 2022-2024 lax1dude. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -18,7 +18,7 @@ import net.lax1dude.unsafememcpy.UnsafeUtils; * POSSIBILITY OF SUCH DAMAGE. * */ -public class EaglerLWJGLIntBuffer implements IntBuffer { +public class EaglerLWJGLIntBuffer extends IntBuffer { final long address; final boolean original; diff --git a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLShortBuffer.java b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLShortBuffer.java index 094153da..c77a0ce5 100755 --- a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLShortBuffer.java +++ b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLShortBuffer.java @@ -4,7 +4,7 @@ import net.lax1dude.unsafememcpy.UnsafeMemcpy; import net.lax1dude.unsafememcpy.UnsafeUtils; /** - * Copyright (c) 2022-2024 lax1dude. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -18,7 +18,7 @@ import net.lax1dude.unsafememcpy.UnsafeUtils; * POSSIBILITY OF SUCH DAMAGE. * */ -public class EaglerLWJGLShortBuffer implements ShortBuffer { +public class EaglerLWJGLShortBuffer extends ShortBuffer { final long address; final boolean original; diff --git a/src/main/java/com/carrotsearch/hppc/AbstractByteCollection.java b/src/main/java/com/carrotsearch/hppc/AbstractByteCollection.java new file mode 100755 index 00000000..ed184354 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/AbstractByteCollection.java @@ -0,0 +1,51 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ByteCursor; +import com.carrotsearch.hppc.predicates.BytePredicate; +import java.util.Arrays; + +/** Common superclass for collections. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "AbstractKTypeCollection.java") +abstract class AbstractByteCollection implements ByteCollection { + /** Default implementation uses a predicate for removal. */ + @Override + public int removeAll(final ByteLookupContainer c) { + return this.removeAll(c::contains); + } + + /** Default implementation uses a predicate for retaining. */ + @Override + public int retainAll(final ByteLookupContainer c) { + // We know c holds sub-types of byte and we're not modifying c, so go unchecked. + return this.removeAll(k -> !c.contains(k)); + } + + /** + * Default implementation redirects to {@link #removeAll(BytePredicate)} and negates the + * predicate. + */ + @Override + public int retainAll(final BytePredicate predicate) { + return removeAll(value -> !predicate.apply(value)); + } + + /** Default implementation of copying to an array. */ + @Override + public byte[] toArray() { + + byte[] array = (new byte[size()]); + int i = 0; + for (ByteCursor c : this) { + array[i++] = c.value; + } + return array; + } + + /** Convert the contents of this container to a human-friendly string. */ + @Override + public String toString() { + return Arrays.toString(this.toArray()); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/AbstractCharCollection.java b/src/main/java/com/carrotsearch/hppc/AbstractCharCollection.java new file mode 100755 index 00000000..5ecdbb55 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/AbstractCharCollection.java @@ -0,0 +1,51 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.CharCursor; +import com.carrotsearch.hppc.predicates.CharPredicate; +import java.util.Arrays; + +/** Common superclass for collections. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "AbstractKTypeCollection.java") +abstract class AbstractCharCollection implements CharCollection { + /** Default implementation uses a predicate for removal. */ + @Override + public int removeAll(final CharLookupContainer c) { + return this.removeAll(c::contains); + } + + /** Default implementation uses a predicate for retaining. */ + @Override + public int retainAll(final CharLookupContainer c) { + // We know c holds sub-types of char and we're not modifying c, so go unchecked. + return this.removeAll(k -> !c.contains(k)); + } + + /** + * Default implementation redirects to {@link #removeAll(CharPredicate)} and negates the + * predicate. + */ + @Override + public int retainAll(final CharPredicate predicate) { + return removeAll(value -> !predicate.apply(value)); + } + + /** Default implementation of copying to an array. */ + @Override + public char[] toArray() { + + char[] array = (new char[size()]); + int i = 0; + for (CharCursor c : this) { + array[i++] = c.value; + } + return array; + } + + /** Convert the contents of this container to a human-friendly string. */ + @Override + public String toString() { + return Arrays.toString(this.toArray()); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/AbstractDoubleCollection.java b/src/main/java/com/carrotsearch/hppc/AbstractDoubleCollection.java new file mode 100755 index 00000000..2bb296ff --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/AbstractDoubleCollection.java @@ -0,0 +1,51 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.DoubleCursor; +import com.carrotsearch.hppc.predicates.DoublePredicate; +import java.util.Arrays; + +/** Common superclass for collections. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "AbstractKTypeCollection.java") +abstract class AbstractDoubleCollection implements DoubleCollection { + /** Default implementation uses a predicate for removal. */ + @Override + public int removeAll(final DoubleLookupContainer c) { + return this.removeAll(c::contains); + } + + /** Default implementation uses a predicate for retaining. */ + @Override + public int retainAll(final DoubleLookupContainer c) { + // We know c holds sub-types of double and we're not modifying c, so go unchecked. + return this.removeAll(k -> !c.contains(k)); + } + + /** + * Default implementation redirects to {@link #removeAll(DoublePredicate)} and negates the + * predicate. + */ + @Override + public int retainAll(final DoublePredicate predicate) { + return removeAll(value -> !predicate.apply(value)); + } + + /** Default implementation of copying to an array. */ + @Override + public double[] toArray() { + + double[] array = (new double[size()]); + int i = 0; + for (DoubleCursor c : this) { + array[i++] = c.value; + } + return array; + } + + /** Convert the contents of this container to a human-friendly string. */ + @Override + public String toString() { + return Arrays.toString(this.toArray()); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/AbstractFloatCollection.java b/src/main/java/com/carrotsearch/hppc/AbstractFloatCollection.java new file mode 100755 index 00000000..089086f8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/AbstractFloatCollection.java @@ -0,0 +1,51 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.FloatCursor; +import com.carrotsearch.hppc.predicates.FloatPredicate; +import java.util.Arrays; + +/** Common superclass for collections. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "AbstractKTypeCollection.java") +abstract class AbstractFloatCollection implements FloatCollection { + /** Default implementation uses a predicate for removal. */ + @Override + public int removeAll(final FloatLookupContainer c) { + return this.removeAll(c::contains); + } + + /** Default implementation uses a predicate for retaining. */ + @Override + public int retainAll(final FloatLookupContainer c) { + // We know c holds sub-types of float and we're not modifying c, so go unchecked. + return this.removeAll(k -> !c.contains(k)); + } + + /** + * Default implementation redirects to {@link #removeAll(FloatPredicate)} and negates the + * predicate. + */ + @Override + public int retainAll(final FloatPredicate predicate) { + return removeAll(value -> !predicate.apply(value)); + } + + /** Default implementation of copying to an array. */ + @Override + public float[] toArray() { + + float[] array = (new float[size()]); + int i = 0; + for (FloatCursor c : this) { + array[i++] = c.value; + } + return array; + } + + /** Convert the contents of this container to a human-friendly string. */ + @Override + public String toString() { + return Arrays.toString(this.toArray()); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/AbstractIntCollection.java b/src/main/java/com/carrotsearch/hppc/AbstractIntCollection.java new file mode 100755 index 00000000..e9ae748d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/AbstractIntCollection.java @@ -0,0 +1,50 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.IntCursor; +import com.carrotsearch.hppc.predicates.IntPredicate; +import java.util.Arrays; + +/** Common superclass for collections. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "AbstractKTypeCollection.java") +abstract class AbstractIntCollection implements IntCollection { + /** Default implementation uses a predicate for removal. */ + @Override + public int removeAll(final IntLookupContainer c) { + return this.removeAll(c::contains); + } + + /** Default implementation uses a predicate for retaining. */ + @Override + public int retainAll(final IntLookupContainer c) { + // We know c holds sub-types of int and we're not modifying c, so go unchecked. + return this.removeAll(k -> !c.contains(k)); + } + + /** + * Default implementation redirects to {@link #removeAll(IntPredicate)} and negates the predicate. + */ + @Override + public int retainAll(final IntPredicate predicate) { + return removeAll(value -> !predicate.apply(value)); + } + + /** Default implementation of copying to an array. */ + @Override + public int[] toArray() { + + int[] array = (new int[size()]); + int i = 0; + for (IntCursor c : this) { + array[i++] = c.value; + } + return array; + } + + /** Convert the contents of this container to a human-friendly string. */ + @Override + public String toString() { + return Arrays.toString(this.toArray()); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/AbstractIterator.java b/src/main/java/com/carrotsearch/hppc/AbstractIterator.java new file mode 100755 index 00000000..78951402 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/AbstractIterator.java @@ -0,0 +1,71 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** Simplifies the implementation of iterators a bit. Modeled loosely after Google Guava's API. */ +public abstract class AbstractIterator implements Iterator { + private static final int NOT_CACHED = 0; + private static final int CACHED = 1; + private static final int AT_END = 2; + + /** Current iterator state. */ + private int state = NOT_CACHED; + + /** The next element to be returned from {@link #next()} if fetched. */ + private E nextElement; + + /** {@inheritDoc} */ + @Override + public boolean hasNext() { + if (state == NOT_CACHED) { + state = CACHED; + nextElement = fetch(); + } + return state == CACHED; + } + + /** {@inheritDoc} */ + @Override + public E next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + state = NOT_CACHED; + return nextElement; + } + + /** Default implementation throws {@link UnsupportedOperationException}. */ + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + /** + * Fetch next element. The implementation must return {@link #done()} when all elements have been + * fetched. + * + * @return Returns the next value for the iterator or chain-calls {@link #done()}. + */ + protected abstract E fetch(); + + /** + * Call when done. + * + * @return Returns a unique sentinel value to indicate end-of-iteration. + */ + protected final E done() { + state = AT_END; + return null; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/AbstractLongCollection.java b/src/main/java/com/carrotsearch/hppc/AbstractLongCollection.java new file mode 100755 index 00000000..914bc36e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/AbstractLongCollection.java @@ -0,0 +1,51 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.LongCursor; +import com.carrotsearch.hppc.predicates.LongPredicate; +import java.util.Arrays; + +/** Common superclass for collections. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "AbstractKTypeCollection.java") +abstract class AbstractLongCollection implements LongCollection { + /** Default implementation uses a predicate for removal. */ + @Override + public int removeAll(final LongLookupContainer c) { + return this.removeAll(c::contains); + } + + /** Default implementation uses a predicate for retaining. */ + @Override + public int retainAll(final LongLookupContainer c) { + // We know c holds sub-types of long and we're not modifying c, so go unchecked. + return this.removeAll(k -> !c.contains(k)); + } + + /** + * Default implementation redirects to {@link #removeAll(LongPredicate)} and negates the + * predicate. + */ + @Override + public int retainAll(final LongPredicate predicate) { + return removeAll(value -> !predicate.apply(value)); + } + + /** Default implementation of copying to an array. */ + @Override + public long[] toArray() { + + long[] array = (new long[size()]); + int i = 0; + for (LongCursor c : this) { + array[i++] = c.value; + } + return array; + } + + /** Convert the contents of this container to a human-friendly string. */ + @Override + public String toString() { + return Arrays.toString(this.toArray()); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/AbstractObjectCollection.java b/src/main/java/com/carrotsearch/hppc/AbstractObjectCollection.java new file mode 100755 index 00000000..1a841f62 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/AbstractObjectCollection.java @@ -0,0 +1,66 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ObjectCursor; +import com.carrotsearch.hppc.predicates.ObjectPredicate; +import java.util.Arrays; + +/** Common superclass for collections. */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "AbstractKTypeCollection.java") +abstract class AbstractObjectCollection implements ObjectCollection { + /** Default implementation uses a predicate for removal. */ + @Override + public int removeAll(final ObjectLookupContainer c) { + return this.removeAll(c::contains); + } + + /** Default implementation uses a predicate for retaining. */ + @Override + public int retainAll(final ObjectLookupContainer c) { + // We know c holds sub-types of Object and we're not modifying c, so go unchecked. + return this.removeAll(k -> !c.contains(k)); + } + + /** + * Default implementation redirects to {@link #removeAll(ObjectPredicate)} and negates the + * predicate. + */ + @Override + public int retainAll(final ObjectPredicate predicate) { + return removeAll(value -> !predicate.apply(value)); + } + + /** Default implementation of copying to an array. */ + @Override + public Object[] toArray() { + + KType[] array = ((KType[]) new Object[size()]); + int i = 0; + for (ObjectCursor c : this) { + array[i++] = c.value; + } + return array; + } + + public T[] toArray(Class componentClass) { + final int size = size(); + final T[] array = (T[]) java.lang.reflect.Array.newInstance(componentClass, size); + int i = 0; + for (ObjectCursor c : this) { + array[i++] = (T) c.value; + } + return array; + } + + /** Convert the contents of this container to a human-friendly string. */ + @Override + public String toString() { + return Arrays.toString(this.toArray()); + } + + protected boolean equals(Object v1, Object v2) { + return (v1 == v2) || (v1 != null && v1.equals(v2)); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/AbstractShortCollection.java b/src/main/java/com/carrotsearch/hppc/AbstractShortCollection.java new file mode 100755 index 00000000..e78dbe11 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/AbstractShortCollection.java @@ -0,0 +1,51 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ShortCursor; +import com.carrotsearch.hppc.predicates.ShortPredicate; +import java.util.Arrays; + +/** Common superclass for collections. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "AbstractKTypeCollection.java") +abstract class AbstractShortCollection implements ShortCollection { + /** Default implementation uses a predicate for removal. */ + @Override + public int removeAll(final ShortLookupContainer c) { + return this.removeAll(c::contains); + } + + /** Default implementation uses a predicate for retaining. */ + @Override + public int retainAll(final ShortLookupContainer c) { + // We know c holds sub-types of short and we're not modifying c, so go unchecked. + return this.removeAll(k -> !c.contains(k)); + } + + /** + * Default implementation redirects to {@link #removeAll(ShortPredicate)} and negates the + * predicate. + */ + @Override + public int retainAll(final ShortPredicate predicate) { + return removeAll(value -> !predicate.apply(value)); + } + + /** Default implementation of copying to an array. */ + @Override + public short[] toArray() { + + short[] array = (new short[size()]); + int i = 0; + for (ShortCursor c : this) { + array[i++] = c.value; + } + return array; + } + + /** Convert the contents of this container to a human-friendly string. */ + @Override + public String toString() { + return Arrays.toString(this.toArray()); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/Accountable.java b/src/main/java/com/carrotsearch/hppc/Accountable.java new file mode 100755 index 00000000..44aefc9b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/Accountable.java @@ -0,0 +1,31 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc; + +/** + * Anything that could be accounted for memory usage + * + *

Partly forked from Lucene tag releases/lucene-solr/8.5.1 + */ +public interface Accountable { + /** + * Allocated memory estimation + * + * @return Ram allocated in bytes + */ + long ramBytesAllocated(); + + /** + * Bytes that is actually been used + * + * @return Ram used in bytes + */ + long ramBytesUsed(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ArraySizingStrategy.java b/src/main/java/com/carrotsearch/hppc/ArraySizingStrategy.java new file mode 100755 index 00000000..b541c56f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ArraySizingStrategy.java @@ -0,0 +1,27 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc; + +/** Resizing (growth) strategy for array-backed buffers. */ +public interface ArraySizingStrategy extends Accountable { + /** + * @param currentBufferLength Current size of the array (buffer). This number should comply with + * the strategy's policies (it is a result of initial rounding or further growCalls). It can + * also be zero, indicating the growth from an empty buffer. + * @param elementsCount Number of elements stored in the buffer. + * @param expectedAdditions Expected number of additions (resize hint). + * @return Must return a new size at least as big as to hold + * elementsCount + expectedAdditions. + * @throws BufferAllocationException If the sizing strategy cannot grow the buffer (for example + * due to constraints or memory limits). + */ + int grow(int currentBufferLength, int elementsCount, int expectedAdditions) + throws BufferAllocationException; +} diff --git a/src/main/java/com/carrotsearch/hppc/BitMixer.java b/src/main/java/com/carrotsearch/hppc/BitMixer.java new file mode 100755 index 00000000..136c12f9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/BitMixer.java @@ -0,0 +1,120 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc; + +/** + * Bit mixing utilities. The purpose of these methods is to evenly distribute key space over int32 + * range. + */ +public final class BitMixer { + + // Don't bother mixing very small key domains much. + public static int mix(byte key) { + return key * PHI_C32; + } + + public static int mix(short key) { + return mixPhi(key); + } + + public static int mix(char key) { + return mixPhi(key); + } + + // Better mix for larger key domains. + public static int mix(int key) { + return mix32(key); + } + + public static int mix(float key) { + return mix32(Float.floatToIntBits(key)); + } + + public static int mix(double key) { + return (int) mix64(Double.doubleToLongBits(key)); + } + + public static int mix(long key) { + return (int) mix64(key); + } + + public static int mix(Object key) { + return key == null ? 0 : mix32(key.hashCode()); + } + + /** MH3's plain finalization step. */ + public static int mix32(int k) { + k = (k ^ (k >>> 16)) * 0x85ebca6b; + k = (k ^ (k >>> 13)) * 0xc2b2ae35; + return k ^ (k >>> 16); + } + + /** + * Computes David Stafford variant 9 of 64bit mix function (MH3 finalization step, with different + * shifts and constants). + * + *

Variant 9 is picked because it contains two 32-bit shifts which could be possibly optimized + * into better machine code. + * + * @see "http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html" + */ + public static long mix64(long z) { + z = (z ^ (z >>> 32)) * 0x4cd6944c5cc20b6dL; + z = (z ^ (z >>> 29)) * 0xfc12c5b19d3259e9L; + return z ^ (z >>> 32); + } + + /* + * Golden ratio bit mixers. + */ + + private static final int PHI_C32 = 0x9e3779b9; + private static final long PHI_C64 = 0x9e3779b97f4a7c15L; + + public static int mixPhi(byte k) { + final int h = k * PHI_C32; + return h ^ (h >>> 16); + } + + public static int mixPhi(char k) { + final int h = k * PHI_C32; + return h ^ (h >>> 16); + } + + public static int mixPhi(short k) { + final int h = k * PHI_C32; + return h ^ (h >>> 16); + } + + public static int mixPhi(int k) { + final int h = k * PHI_C32; + return h ^ (h >>> 16); + } + + public static int mixPhi(float k) { + final int h = Float.floatToIntBits(k) * PHI_C32; + return h ^ (h >>> 16); + } + + public static int mixPhi(double k) { + final long h = Double.doubleToLongBits(k) * PHI_C64; + return (int) (h ^ (h >>> 32)); + } + + public static int mixPhi(long k) { + final long h = k * PHI_C64; + return (int) (h ^ (h >>> 32)); + } + + public static int mixPhi(Object k) { + final int h = (k == null ? 0 : k.hashCode() * PHI_C32); + return h ^ (h >>> 16); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/BitSet.java b/src/main/java/com/carrotsearch/hppc/BitSet.java new file mode 100755 index 00000000..7f8a94bc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/BitSet.java @@ -0,0 +1,952 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.IntCursor; +import com.carrotsearch.hppc.cursors.LongCursor; +import com.carrotsearch.hppc.predicates.IntPredicate; +import com.carrotsearch.hppc.predicates.LongPredicate; +import com.carrotsearch.hppc.procedures.IntProcedure; +import com.carrotsearch.hppc.procedures.LongProcedure; +import java.util.*; + +/** + * An "open" BitSet implementation that allows direct access to the array of words storing the bits. + * + *

Unlike {@link java.util.BitSet}, the fact that bits are packed into an array of longs is part + * of the interface. This allows efficient implementation of other algorithms by someone other than + * the author. It also allows one to efficiently implement alternate serialization or interchange + * formats. + * + *

The index range for a bitset can easily exceed positive int range in Java + * (0x7fffffff), so many methods in this class accept or return a long. There are + * adapter methods that return views compatible with {@link LongLookupContainer} and {@link + * IntLookupContainer} interfaces. + * + * @see #asIntLookupContainer() + * @see #asLongLookupContainer() + */ +public class BitSet implements Cloneable { + /** The initial default number of bits. */ + private static final long DEFAULT_NUM_BITS = 64; + + /** Internal representation of bits in this bit set. */ + public long[] bits; + + /** The number of words (longs) used in the {@link #bits} array. */ + public int wlen; + + /** Constructs a bit set with the default capacity. */ + public BitSet() { + this(DEFAULT_NUM_BITS); + } + + /** + * Constructs an BitSet large enough to hold numBits. + * + * @param numBits Number of bits + */ + public BitSet(long numBits) { + bits = new long[bits2words(numBits)]; + wlen = bits.length; + } + + /** + * Constructs an BitSet from an existing long[]. + * + *

The first 64 bits are in long[0], with bit index 0 at the least significant bit, and bit + * index 63 at the most significant. Given a bit index, the word containing it is long[index/64], + * and it is at bit number index%64 within that word. + * + *

numWords are the number of elements in the array that contain set bits (non-zero longs). + * numWords should be <= bits.length, and any existing words in the array at position >= + * numWords should be zero. + * + * @param bits underlying bits buffer + * @param numWords the number of elements in the array that contain set bits + */ + public BitSet(long[] bits, int numWords) { + this.bits = bits; + this.wlen = numWords; + } + + /** + * Static constructor-like method similar to other (generic) collections. + * + * @return New instance. + */ + public static BitSet newInstance() { + return new BitSet(); + } + + /** + * @return Returns an iterator over all set bits of this bitset. The iterator should be faster + * than using a loop around {@link #nextSetBit(int)}. + */ + public BitSetIterator iterator() { + return new BitSetIterator(bits, wlen); + } + + /** + * @return Returns the current capacity in bits (1 greater than the index of the last bit). + */ + public long capacity() { + return bits.length << 6; + } + + /** + * @see #cardinality() + * @see java.util.BitSet#size() + * @return Returns the current capacity of this set. Included for compatibility. This is + * not equal to {@link #cardinality}. + */ + public long size() { + return capacity(); + } + + /** + * @see java.util.BitSet#length() + * @return Returns the "logical size" of this {@code BitSet}: the index of the highest set bit in + * the {@code BitSet} plus one. + */ + public long length() { + trimTrailingZeros(); + if (wlen == 0) return 0; + return (((long) wlen - 1) << 6) + (64 - Long.numberOfLeadingZeros(bits[wlen - 1])); + } + + /** + * @return Returns true if there are no set bits + */ + public boolean isEmpty() { + return cardinality() == 0; + } + + /** + * @param index The index. + * @return Returns true or false for the specified bit index. + */ + public boolean get(int index) { + int i = index >> 6; // div 64 + // signed shift will keep a negative index and force an + // array-index-out-of-bounds-exception, removing the need for an explicit check. + if (i >= bits.length) return false; + + int bit = index & 0x3f; // mod 64 + long bitmask = 1L << bit; + return (bits[i] & bitmask) != 0; + } + + /** + * @param index The index. + * @return Returns true or false for the specified bit index. + */ + public boolean get(long index) { + int i = (int) (index >> 6); // div 64 + if (i >= bits.length) return false; + int bit = (int) index & 0x3f; // mod 64 + long bitmask = 1L << bit; + return (bits[i] & bitmask) != 0; + } + + /** + * Sets a bit, expanding the set size if necessary. + * + * @param index the index to set + */ + public void set(long index) { + int wordNum = expandingWordNum(index); + int bit = (int) index & 0x3f; + long bitmask = 1L << bit; + bits[wordNum] |= bitmask; + } + + /** + * Sets a range of bits, expanding the set size if necessary + * + * @param startIndex lower index + * @param endIndex one-past the last bit to set + */ + public void set(long startIndex, long endIndex) { + if (endIndex <= startIndex) return; + + int startWord = (int) (startIndex >> 6); + + // since endIndex is one past the end, this is index of the last + // word to be changed. + int endWord = expandingWordNum(endIndex - 1); + + long startmask = -1L << startIndex; + long endmask = -1L >>> -endIndex; // 64-(endIndex&0x3f) is the same as -endIndex + // due to wrap + + if (startWord == endWord) { + bits[startWord] |= (startmask & endmask); + return; + } + + bits[startWord] |= startmask; + Arrays.fill(bits, startWord + 1, endWord, -1L); + bits[endWord] |= endmask; + } + + protected int expandingWordNum(long index) { + int wordNum = (int) (index >> 6); + if (wordNum >= wlen) { + ensureCapacity(index + 1); + wlen = wordNum + 1; + } + return wordNum; + } + + /** Clears all bits. */ + public void clear() { + Arrays.fill(bits, 0); + this.wlen = 0; + } + + /** + * clears a bit, allowing access beyond the current set size without changing the size. + * + * @param index the index to clear + */ + public void clear(long index) { + int wordNum = (int) (index >> 6); // div 64 + if (wordNum >= wlen) return; + int bit = (int) index & 0x3f; // mod 64 + long bitmask = 1L << bit; + bits[wordNum] &= ~bitmask; + } + + /** + * Clears a range of bits. Clearing past the end does not change the size of the set. + * + * @param startIndex lower index + * @param endIndex one-past the last bit to clear + */ + public void clear(int startIndex, int endIndex) { + if (endIndex <= startIndex) return; + + int startWord = (startIndex >> 6); + if (startWord >= wlen) return; + + // since endIndex is one past the end, this is index of the last + // word to be changed. + int endWord = ((endIndex - 1) >> 6); + + long startmask = -1L << startIndex; + long endmask = -1L >>> -endIndex; // 64-(endIndex&0x3f) is the same as -endIndex + // due to wrap + + // invert masks since we are clearing + startmask = ~startmask; + endmask = ~endmask; + + if (startWord == endWord) { + bits[startWord] &= (startmask | endmask); + return; + } + + bits[startWord] &= startmask; + + int middle = Math.min(wlen, endWord); + Arrays.fill(bits, startWord + 1, middle, 0L); + if (endWord < wlen) { + bits[endWord] &= endmask; + } + } + + /** + * Clears a range of bits. Clearing past the end does not change the size of the set. + * + * @param startIndex lower index + * @param endIndex one-past the last bit to clear + */ + public void clear(long startIndex, long endIndex) { + if (endIndex <= startIndex) return; + + int startWord = (int) (startIndex >> 6); + if (startWord >= wlen) return; + + // since endIndex is one past the end, this is index of the last + // word to be changed. + int endWord = (int) ((endIndex - 1) >> 6); + + long startmask = -1L << startIndex; + long endmask = -1L >>> -endIndex; // 64-(endIndex&0x3f) is the same as -endIndex + // due to wrap + + // invert masks since we are clearing + startmask = ~startmask; + endmask = ~endmask; + + if (startWord == endWord) { + bits[startWord] &= (startmask | endmask); + return; + } + + bits[startWord] &= startmask; + + int middle = Math.min(wlen, endWord); + Arrays.fill(bits, startWord + 1, middle, 0L); + if (endWord < wlen) { + bits[endWord] &= endmask; + } + } + + /** + * Sets a bit and returns the previous value. The index should be less than the BitSet size. + * + * @param index the index to set + * @return previous state of the index + */ + public boolean getAndSet(int index) { + int wordNum = index >> 6; // div 64 + int bit = index & 0x3f; // mod 64 + long bitmask = 1L << bit; + boolean val = (bits[wordNum] & bitmask) != 0; + bits[wordNum] |= bitmask; + return val; + } + + /** + * Sets a bit and returns the previous value. The index should be less than the BitSet size. + * + * @param index the index to set + * @return previous state of the index + */ + public boolean getAndSet(long index) { + int wordNum = (int) (index >> 6); // div 64 + int bit = (int) index & 0x3f; // mod 64 + long bitmask = 1L << bit; + boolean val = (bits[wordNum] & bitmask) != 0; + bits[wordNum] |= bitmask; + return val; + } + + /** + * Flips a bit, expanding the set size if necessary. + * + * @param index the index to flip + */ + public void flip(long index) { + int wordNum = expandingWordNum(index); + int bit = (int) index & 0x3f; // mod 64 + long bitmask = 1L << bit; + bits[wordNum] ^= bitmask; + } + + /** + * flips a bit and returns the resulting bit value. The index should be less than the BitSet size. + * + * @param index the index to flip + * @return previous state of the index + */ + public boolean flipAndGet(int index) { + int wordNum = index >> 6; // div 64 + int bit = index & 0x3f; // mod 64 + long bitmask = 1L << bit; + bits[wordNum] ^= bitmask; + return (bits[wordNum] & bitmask) != 0; + } + + /** + * flips a bit and returns the resulting bit value. The index should be less than the BitSet size. + * + * @param index the index to flip + * @return previous state of the index + */ + public boolean flipAndGet(long index) { + int wordNum = (int) (index >> 6); // div 64 + int bit = (int) index & 0x3f; // mod 64 + long bitmask = 1L << bit; + bits[wordNum] ^= bitmask; + return (bits[wordNum] & bitmask) != 0; + } + + /** + * Flips a range of bits, expanding the set size if necessary + * + * @param startIndex lower index + * @param endIndex one-past the last bit to flip + */ + public void flip(long startIndex, long endIndex) { + if (endIndex <= startIndex) return; + int startWord = (int) (startIndex >> 6); + + // since endIndex is one past the end, this is index of the last + // word to be changed. + int endWord = expandingWordNum(endIndex - 1); + + long startmask = -1L << startIndex; + long endmask = -1L >>> -endIndex; // 64-(endIndex&0x3f) is the same as -endIndex + // due to wrap + + if (startWord == endWord) { + bits[startWord] ^= (startmask & endmask); + return; + } + + bits[startWord] ^= startmask; + + for (int i = startWord + 1; i < endWord; i++) { + bits[i] = ~bits[i]; + } + + bits[endWord] ^= endmask; + } + + /** + * @return the number of set bits + */ + public long cardinality() { + return BitUtil.pop_array(bits, 0, wlen); + } + + /** + * @param a The first set + * @param b The second set + * @return Returns the popcount or cardinality of the intersection of the two sets. Neither set is + * modified. + */ + public static long intersectionCount(BitSet a, BitSet b) { + return BitUtil.pop_intersect(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen)); + } + + /** + * @param a The first set + * @param b The second set + * @return Returns the popcount or cardinality of the union of the two sets. Neither set is + * modified. + */ + public static long unionCount(BitSet a, BitSet b) { + long tot = BitUtil.pop_union(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen)); + if (a.wlen < b.wlen) { + tot += BitUtil.pop_array(b.bits, a.wlen, b.wlen - a.wlen); + } else if (a.wlen > b.wlen) { + tot += BitUtil.pop_array(a.bits, b.wlen, a.wlen - b.wlen); + } + return tot; + } + + /** + * @param a The first set + * @param b The second set + * @return Returns the popcount or cardinality of "a and not b" or "intersection(a, not(b))". + * Neither set is modified. + */ + public static long andNotCount(BitSet a, BitSet b) { + long tot = BitUtil.pop_andnot(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen)); + if (a.wlen > b.wlen) { + tot += BitUtil.pop_array(a.bits, b.wlen, a.wlen - b.wlen); + } + return tot; + } + + /** + * @param a The first set + * @param b The second set + * @return Returns the popcount or cardinality of the exclusive-or of the two sets. Neither set is + * modified. + */ + public static long xorCount(BitSet a, BitSet b) { + long tot = BitUtil.pop_xor(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen)); + if (a.wlen < b.wlen) { + tot += BitUtil.pop_array(b.bits, a.wlen, b.wlen - a.wlen); + } else if (a.wlen > b.wlen) { + tot += BitUtil.pop_array(a.bits, b.wlen, a.wlen - b.wlen); + } + return tot; + } + + /** + * @param index The index to start scanning from, inclusive. + * @return Returns the index of the first set bit starting at the index specified. -1 is returned + * if there are no more set bits. + */ + public int nextSetBit(int index) { + int i = index >> 6; + if (i >= wlen) return -1; + int subIndex = index & 0x3f; // index within the word + long word = bits[i] >> subIndex; // skip all the bits to the right of index + + if (word != 0) { + return (i << 6) + subIndex + Long.numberOfTrailingZeros(word); + } + + while (++i < wlen) { + word = bits[i]; + if (word != 0) return (i << 6) + Long.numberOfTrailingZeros(word); + } + + return -1; + } + + /** + * @param index The index to start scanning from, inclusive. + * @return Returns the index of the first set bit starting at the index specified. -1 is returned + * if there are no more set bits. + */ + public long nextSetBit(long index) { + int i = (int) (index >>> 6); + if (i >= wlen) return -1; + int subIndex = (int) index & 0x3f; // index within the word + long word = bits[i] >>> subIndex; // skip all the bits to the right of index + + if (word != 0) { + return (((long) i) << 6) + (subIndex + Long.numberOfTrailingZeros(word)); + } + + while (++i < wlen) { + word = bits[i]; + if (word != 0) return (((long) i) << 6) + Long.numberOfTrailingZeros(word); + } + + return -1; + } + + @Override + public Object clone() { + try { + BitSet obs = (BitSet) super.clone(); + obs.bits = (long[]) obs.bits.clone(); // hopefully an array clone is as + // fast(er) than arraycopy + return obs; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** + * this = this AND other + * + * @param other The bitset to intersect with. + */ + public void intersect(BitSet other) { + int newLen = Math.min(this.wlen, other.wlen); + long[] thisArr = this.bits; + long[] otherArr = other.bits; + // testing against zero can be more efficient + int pos = newLen; + while (--pos >= 0) { + thisArr[pos] &= otherArr[pos]; + } + if (this.wlen > newLen) { + // fill zeros from the new shorter length to the old length + Arrays.fill(bits, newLen, this.wlen, 0); + } + this.wlen = newLen; + } + + /** + * this = this OR other + * + * @param other The bitset to union with. + */ + public void union(BitSet other) { + int newLen = Math.max(wlen, other.wlen); + ensureCapacityWords(newLen); + + long[] thisArr = this.bits; + long[] otherArr = other.bits; + int pos = Math.min(wlen, other.wlen); + while (--pos >= 0) { + thisArr[pos] |= otherArr[pos]; + } + if (this.wlen < newLen) { + System.arraycopy(otherArr, this.wlen, thisArr, this.wlen, newLen - this.wlen); + } + this.wlen = newLen; + } + + /** + * Remove all elements set in other: this = this AND_NOT other + * + * @param other The other bitset. + */ + public void remove(BitSet other) { + int idx = Math.min(wlen, other.wlen); + long[] thisArr = this.bits; + long[] otherArr = other.bits; + while (--idx >= 0) { + thisArr[idx] &= ~otherArr[idx]; + } + } + + /** + * this = this XOR other + * + * @param other The other bitset. + */ + public void xor(BitSet other) { + int newLen = Math.max(wlen, other.wlen); + ensureCapacityWords(newLen); + + long[] thisArr = this.bits; + long[] otherArr = other.bits; + int pos = Math.min(wlen, other.wlen); + while (--pos >= 0) { + thisArr[pos] ^= otherArr[pos]; + } + if (this.wlen < newLen) { + System.arraycopy(otherArr, this.wlen, thisArr, this.wlen, newLen - this.wlen); + } + this.wlen = newLen; + } + + // some BitSet compatibility methods + + // ** see {@link intersect} */ + public void and(BitSet other) { + intersect(other); + } + + // ** see {@link union} */ + public void or(BitSet other) { + union(other); + } + + // ** see {@link andNot} */ + public void andNot(BitSet other) { + remove(other); + } + + /** + * @param other The other bitset. + * @return true if the sets have any elements in common + */ + public boolean intersects(BitSet other) { + int pos = Math.min(this.wlen, other.wlen); + long[] thisArr = this.bits; + long[] otherArr = other.bits; + while (--pos >= 0) { + if ((thisArr[pos] & otherArr[pos]) != 0) return true; + } + return false; + } + + /** + * Expand the long[] with the size given as a number of words (64 bit longs). getNumWords() is + * unchanged by this call. + * + * @param numWords The size to expand to (64-bit long words) + */ + public void ensureCapacityWords(int numWords) { + if (bits.length < numWords) { + bits = grow(bits, numWords); + } + } + + public static long[] grow(long[] array, int minSize) { + if (array.length < minSize) { + long[] newArray = new long[getNextSize(minSize)]; + System.arraycopy(array, 0, newArray, 0, array.length); + return newArray; + } else return array; + } + + public static int getNextSize(int targetSize) { + /* + * This over-allocates proportional to the list size, making room for additional + * growth. The over-allocation is mild, but is enough to give linear-time + * amortized behavior over a long sequence of appends() in the presence of a + * poorly-performing system realloc(). The growth pattern is: 0, 4, 8, 16, 25, 35, + * 46, 58, 72, 88, ... + */ + return (targetSize >> 3) + (targetSize < 9 ? 3 : 6) + targetSize; + } + + /** + * Ensure that the long[] is big enough to hold numBits, expanding it if necessary. getNumWords() + * is unchanged by this call. + * + * @param numBits The number of bits to expand to + */ + public void ensureCapacity(long numBits) { + ensureCapacityWords(bits2words(numBits)); + } + + /** Lowers {@link #wlen}, the number of words in use, by checking for trailing zero words. */ + public void trimTrailingZeros() { + int idx = wlen - 1; + while (idx >= 0 && bits[idx] == 0) idx--; + wlen = idx + 1; + } + + /* + * returns the number of 64 bit words it would take to hold numBits + */ + public static int bits2words(long numBits) { + return (int) (((numBits - 1) >>> 6) + 1); + } + + /* returns true if both sets have the same bits set */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof BitSet)) return false; + + BitSet a; + BitSet b = (BitSet) o; + + // make a the larger set. + if (b.wlen > this.wlen) { + a = b; + b = this; + } else { + a = this; + } + + // check for any set bits out of the range of b + for (int i = a.wlen - 1; i >= b.wlen; i--) { + if (a.bits[i] != 0) return false; + } + + for (int i = b.wlen - 1; i >= 0; i--) { + if (a.bits[i] != b.bits[i]) return false; + } + + return true; + } + + @Override + public int hashCode() { + // Start with a zero hash and use a mix that results in zero if the input is zero. + // This effectively truncates trailing zeros without an explicit check. + long h = 0; + for (int i = bits.length; --i >= 0; ) { + h ^= bits[i]; + h = (h << 1) | (h >>> 63); // rotate left + } + + // fold leftmost bits into right and add a constant to prevent + // empty sets from returning 0, which is too common. + return (int) ((h >> 32) ^ h) + 0x98761234; + } + + @Override + public String toString() { + long bit = nextSetBit(0); + if (bit < 0) { + return "{}"; + } + + final StringBuilder builder = new StringBuilder(); + builder.append("{"); + + builder.append(Long.toString(bit)); + while ((bit = nextSetBit(bit + 1)) >= 0) { + builder.append(", "); + builder.append(Long.toString(bit)); + } + builder.append("}"); + + return builder.toString(); + } + + /** + * Returns a view over this bitset data compatible with {@link IntLookupContainer}. A new object + * is always returned, but its methods reflect the current state of the bitset (the view is not a + * snapshot). + * + *

Methods of the returned {@link IntLookupContainer} may throw a {@link RuntimeException} if + * the cardinality of this bitset exceeds the int range. + * + * @return The view of this bitset as {@link IntLookupContainer}. + */ + public IntLookupContainer asIntLookupContainer() { + return new IntLookupContainer() { + @Override + public int size() { + return getCurrentCardinality(); + } + + @Override + public boolean isEmpty() { + return BitSet.this.isEmpty(); + } + + @Override + public Iterator iterator() { + return new Iterator() { + private long nextBitSet = BitSet.this.nextSetBit(0); + private final IntCursor cursor = new IntCursor(); + + @Override + public boolean hasNext() { + return nextBitSet >= 0; + } + + @Override + public IntCursor next() { + final long value = nextBitSet; + if (value < 0) throw new NoSuchElementException(); + if (value > Integer.MAX_VALUE) + throw new RuntimeException("BitSet range larger than maximum positive integer."); + + nextBitSet = BitSet.this.nextSetBit(value + 1); + cursor.index = cursor.value = (int) value; + return cursor; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + @Override + public int[] toArray() { + final int[] data = new int[getCurrentCardinality()]; + final BitSetIterator i = BitSet.this.iterator(); + for (int j = 0, bit = i.nextSetBit(); bit >= 0; bit = i.nextSetBit()) { + data[j++] = bit; + } + return data; + } + + @Override + public T forEach(T predicate) { + final BitSetIterator i = BitSet.this.iterator(); + for (int bit = i.nextSetBit(); bit >= 0; bit = i.nextSetBit()) { + if (predicate.apply(bit) == false) break; + } + + return predicate; + } + + @Override + public T forEach(T procedure) { + final BitSetIterator i = BitSet.this.iterator(); + for (int bit = i.nextSetBit(); bit >= 0; bit = i.nextSetBit()) { + procedure.apply(bit); + } + + return procedure; + } + + @Override + public boolean contains(int index) { + return index < 0 || BitSet.this.get(index); + } + + /** + * Rounds the bitset's cardinality to an integer or throws a {@link RuntimeException} if the + * cardinality exceeds maximum int range. + */ + private int getCurrentCardinality() { + long cardinality = BitSet.this.cardinality(); + if (cardinality > Integer.MAX_VALUE) + throw new RuntimeException( + "Bitset is larger than maximum positive integer: " + cardinality); + return (int) cardinality; + } + }; + } + + /** + * Returns a view over this bitset data compatible with {@link LongLookupContainer}. A new object + * is always returned, but its methods reflect the current state of the bitset (the view is not a + * snapshot). + * + * @return The view of this bitset as {@link LongLookupContainer}. + */ + public LongLookupContainer asLongLookupContainer() { + return new LongLookupContainer() { + @Override + public int size() { + return getCurrentCardinality(); + } + + @Override + public boolean isEmpty() { + return BitSet.this.isEmpty(); + } + + @Override + public Iterator iterator() { + return new Iterator() { + private long nextBitSet = BitSet.this.nextSetBit(0); + private final LongCursor cursor = new LongCursor(); + + @Override + public boolean hasNext() { + return nextBitSet >= 0; + } + + @Override + public LongCursor next() { + final long value = nextBitSet; + if (value < 0) throw new NoSuchElementException(); + + nextBitSet = BitSet.this.nextSetBit(value + 1); + cursor.index = (int) value; + cursor.value = value; + return cursor; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + @Override + public long[] toArray() { + final long[] data = new long[getCurrentCardinality()]; + final BitSet bset = BitSet.this; + int j = 0; + for (long bit = bset.nextSetBit((long) 0); bit >= 0; bit = bset.nextSetBit(bit + 1)) { + data[j++] = bit; + } + return data; + } + + @Override + public T forEach(T predicate) { + final BitSet bset = BitSet.this; + for (long bit = bset.nextSetBit((long) 0); bit >= 0; bit = bset.nextSetBit(bit + 1)) { + if (predicate.apply(bit) == false) break; + } + + return predicate; + } + + @Override + public T forEach(T procedure) { + final BitSet bset = BitSet.this; + for (long bit = bset.nextSetBit((long) 0); bit >= 0; bit = bset.nextSetBit(bit + 1)) { + procedure.apply(bit); + } + + return procedure; + } + + @Override + public boolean contains(long index) { + return index < 0 || BitSet.this.get(index); + } + + /** + * Rounds the bitset's cardinality to an integer or throws a {@link RuntimeException} if the + * cardinality exceeds maximum int range. + */ + private int getCurrentCardinality() { + long cardinality = BitSet.this.cardinality(); + if (cardinality > Integer.MAX_VALUE) + throw new RuntimeException( + "Bitset is larger than maximum positive integer: " + cardinality); + return (int) cardinality; + } + }; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/BitSetIterator.java b/src/main/java/com/carrotsearch/hppc/BitSetIterator.java new file mode 100755 index 00000000..35aa3e06 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/BitSetIterator.java @@ -0,0 +1,356 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc; + +/** + * An iterator to iterate over set bits in an BitSet. This is faster than nextSetBit() for iterating + * over the complete set of bits, especially when the density of the bits set is high. + */ +public class BitSetIterator { + // The General Idea: instead of having an array per byte that has + // the offsets of the next set bit, that array could be + // packed inside a 32 bit integer (8 4 bit numbers). That + // should be faster than accessing an array for each index, and + // the total array size is kept smaller (256*sizeof(int))=1K + static final int[] bitlist = { + 0x0, + 0x1, + 0x2, + 0x21, + 0x3, + 0x31, + 0x32, + 0x321, + 0x4, + 0x41, + 0x42, + 0x421, + 0x43, + 0x431, + 0x432, + 0x4321, + 0x5, + 0x51, + 0x52, + 0x521, + 0x53, + 0x531, + 0x532, + 0x5321, + 0x54, + 0x541, + 0x542, + 0x5421, + 0x543, + 0x5431, + 0x5432, + 0x54321, + 0x6, + 0x61, + 0x62, + 0x621, + 0x63, + 0x631, + 0x632, + 0x6321, + 0x64, + 0x641, + 0x642, + 0x6421, + 0x643, + 0x6431, + 0x6432, + 0x64321, + 0x65, + 0x651, + 0x652, + 0x6521, + 0x653, + 0x6531, + 0x6532, + 0x65321, + 0x654, + 0x6541, + 0x6542, + 0x65421, + 0x6543, + 0x65431, + 0x65432, + 0x654321, + 0x7, + 0x71, + 0x72, + 0x721, + 0x73, + 0x731, + 0x732, + 0x7321, + 0x74, + 0x741, + 0x742, + 0x7421, + 0x743, + 0x7431, + 0x7432, + 0x74321, + 0x75, + 0x751, + 0x752, + 0x7521, + 0x753, + 0x7531, + 0x7532, + 0x75321, + 0x754, + 0x7541, + 0x7542, + 0x75421, + 0x7543, + 0x75431, + 0x75432, + 0x754321, + 0x76, + 0x761, + 0x762, + 0x7621, + 0x763, + 0x7631, + 0x7632, + 0x76321, + 0x764, + 0x7641, + 0x7642, + 0x76421, + 0x7643, + 0x76431, + 0x76432, + 0x764321, + 0x765, + 0x7651, + 0x7652, + 0x76521, + 0x7653, + 0x76531, + 0x76532, + 0x765321, + 0x7654, + 0x76541, + 0x76542, + 0x765421, + 0x76543, + 0x765431, + 0x765432, + 0x7654321, + 0x8, + 0x81, + 0x82, + 0x821, + 0x83, + 0x831, + 0x832, + 0x8321, + 0x84, + 0x841, + 0x842, + 0x8421, + 0x843, + 0x8431, + 0x8432, + 0x84321, + 0x85, + 0x851, + 0x852, + 0x8521, + 0x853, + 0x8531, + 0x8532, + 0x85321, + 0x854, + 0x8541, + 0x8542, + 0x85421, + 0x8543, + 0x85431, + 0x85432, + 0x854321, + 0x86, + 0x861, + 0x862, + 0x8621, + 0x863, + 0x8631, + 0x8632, + 0x86321, + 0x864, + 0x8641, + 0x8642, + 0x86421, + 0x8643, + 0x86431, + 0x86432, + 0x864321, + 0x865, + 0x8651, + 0x8652, + 0x86521, + 0x8653, + 0x86531, + 0x86532, + 0x865321, + 0x8654, + 0x86541, + 0x86542, + 0x865421, + 0x86543, + 0x865431, + 0x865432, + 0x8654321, + 0x87, + 0x871, + 0x872, + 0x8721, + 0x873, + 0x8731, + 0x8732, + 0x87321, + 0x874, + 0x8741, + 0x8742, + 0x87421, + 0x8743, + 0x87431, + 0x87432, + 0x874321, + 0x875, + 0x8751, + 0x8752, + 0x87521, + 0x8753, + 0x87531, + 0x87532, + 0x875321, + 0x8754, + 0x87541, + 0x87542, + 0x875421, + 0x87543, + 0x875431, + 0x875432, + 0x8754321, + 0x876, + 0x8761, + 0x8762, + 0x87621, + 0x8763, + 0x87631, + 0x87632, + 0x876321, + 0x8764, + 0x87641, + 0x87642, + 0x876421, + 0x87643, + 0x876431, + 0x876432, + 0x8764321, + 0x8765, + 0x87651, + 0x87652, + 0x876521, + 0x87653, + 0x876531, + 0x876532, + 0x8765321, + 0x87654, + 0x876541, + 0x876542, + 0x8765421, + 0x876543, + 0x8765431, + 0x8765432, + 0x87654321 + }; + + /** + * *** the python code that generated bitlist def bits2int(val): arr=0 for shift in range(8,0,-1): + * if val & 0x80: arr = (arr << 4) | shift val = val << 1 return arr + * + *

def int_table(): tbl = [ hex(bits2int(val)).strip('L') for val in range(256) ] return + * ','.join(tbl) **** + */ + + // hmmm, what about an iterator that finds zeros though, + // or a reverse iterator... should they be separate classes + // for efficiency, or have a common root interface? (or + // maybe both? could ask for a SetBitsIterator, etc... + + private final long[] arr; + + private final int words; + private int i = -1; + private long word; + private int wordShift; + private int indexArray; + + public BitSetIterator(BitSet obs) { + this(obs.bits, obs.wlen); + } + + public BitSetIterator(long[] bits, int numWords) { + arr = bits; + words = numWords; + } + + // 64 bit shifts + private void shift() { + if ((int) word == 0) { + wordShift += 32; + word = word >>> 32; + } + if ((word & 0x0000FFFF) == 0) { + wordShift += 16; + word >>>= 16; + } + if ((word & 0x000000FF) == 0) { + wordShift += 8; + word >>>= 8; + } + indexArray = bitlist[(int) word & 0xff]; + } + + public static final int NO_MORE = -1; + + public int nextSetBit() { + if (indexArray == 0) { + if (word != 0) { + word >>>= 8; + wordShift += 8; + } + + while (word == 0) { + if (++i >= words) { + return NO_MORE; + } + word = arr[i]; + wordShift = -1; // loop invariant code motion should move this + } + + // after the first time, should I go with a linear search, or + // stick with the binary search in shift? + shift(); + } + + int bitIndex = (indexArray & 0x0f) + wordShift; + indexArray >>>= 4; + // should i<<6 be cached as a separate variable? + // it would only save one cycle in the best circumstances. + return (i << 6) + bitIndex; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/BitUtil.java b/src/main/java/com/carrotsearch/hppc/BitUtil.java new file mode 100755 index 00000000..61a628d5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/BitUtil.java @@ -0,0 +1,98 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc; + +/** A variety of high efficiency bit twiddling routines. */ +final class BitUtil { + private BitUtil() {} // no instance + + // The pop methods used to rely on bit-manipulation tricks for speed but it + // turns out that it is faster to use the Long.bitCount method (which is an + // intrinsic since Java 6u18) in a naive loop, see LUCENE-2221 + + /** Returns the number of set bits in an array of longs. */ + public static long pop_array(long[] arr, int wordOffset, int numWords) { + long popCount = 0; + for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) { + popCount += Long.bitCount(arr[i]); + } + return popCount; + } + + /** + * Returns the popcount or cardinality of the two sets after an intersection. Neither array is + * modified. + */ + public static long pop_intersect(long[] arr1, long[] arr2, int wordOffset, int numWords) { + long popCount = 0; + for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) { + popCount += Long.bitCount(arr1[i] & arr2[i]); + } + return popCount; + } + + /** Returns the popcount or cardinality of the union of two sets. Neither array is modified. */ + public static long pop_union(long[] arr1, long[] arr2, int wordOffset, int numWords) { + long popCount = 0; + for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) { + popCount += Long.bitCount(arr1[i] | arr2[i]); + } + return popCount; + } + + /** Returns the popcount or cardinality of A & ~B. Neither array is modified. */ + public static long pop_andnot(long[] arr1, long[] arr2, int wordOffset, int numWords) { + long popCount = 0; + for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) { + popCount += Long.bitCount(arr1[i] & ~arr2[i]); + } + return popCount; + } + + /** Returns the popcount or cardinality of A ^ B Neither array is modified. */ + public static long pop_xor(long[] arr1, long[] arr2, int wordOffset, int numWords) { + long popCount = 0; + for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) { + popCount += Long.bitCount(arr1[i] ^ arr2[i]); + } + return popCount; + } + + /** + * returns the next highest power of two, or the current value if it's already a power of two or + * zero + */ + public static int nextHighestPowerOfTwo(int v) { + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; + } + + /** + * returns the next highest power of two, or the current value if it's already a power of two or + * zero + */ + public static long nextHighestPowerOfTwo(long v) { + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v |= v >> 32; + v++; + return v; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/BoundedProportionalArraySizingStrategy.java b/src/main/java/com/carrotsearch/hppc/BoundedProportionalArraySizingStrategy.java new file mode 100755 index 00000000..14c5a9ab --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/BoundedProportionalArraySizingStrategy.java @@ -0,0 +1,115 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc; + +import java.util.ArrayList; + +/** + * Array resizing proportional to the current buffer size, optionally kept within the given minimum + * and maximum growth limits. Java's {@link ArrayList} uses: + * + *

+ * minGrow = 1
+ * maxGrow = Integer.MAX_VALUE (unbounded)
+ * growRatio = 1.5f
+ * 
+ */ +public final class BoundedProportionalArraySizingStrategy implements ArraySizingStrategy { + + /** Instance of {@link BoundedProportionalArraySizingStrategy} with default values. */ + public static final BoundedProportionalArraySizingStrategy DEFAULT_INSTANCE = + new BoundedProportionalArraySizingStrategy(); + + /** + * Maximum allocable array length (approximately the largest positive integer decreased by the + * array's object header). + */ + public static final int MAX_ARRAY_LENGTH = + Integer.MAX_VALUE - /* aligned array header + slack */ 32; + + /** Minimum grow count. */ + public static final int DEFAULT_MIN_GROW_COUNT = 10; + + /** Maximum grow count (unbounded). */ + public static final int DEFAULT_MAX_GROW_COUNT = MAX_ARRAY_LENGTH; + + /** Default resize is by half the current buffer's size. */ + public static final float DEFAULT_GROW_RATIO = 1.5f; + + /** Minimum number of elements to grow, if limit exceeded. */ + public final int minGrowCount; + + /** Maximum number of elements to grow, if limit exceeded. */ + public final int maxGrowCount; + + /** + * The current buffer length is multiplied by this ratio to get the first estimate for the new + * size. To double the size of the current buffer, for example, set to 2. + */ + public final float growRatio; + + /** Create the default sizing strategy. */ + public BoundedProportionalArraySizingStrategy() { + this(DEFAULT_MIN_GROW_COUNT, DEFAULT_MAX_GROW_COUNT, DEFAULT_GROW_RATIO); + } + + /** + * Create the sizing strategy with custom policies. + * + * @param minGrow Minimum number of elements to grow by when expanding. + * @param maxGrow Maximum number of elements to grow by when expanding. + * @param ratio The ratio of expansion compared to the previous buffer size. + */ + public BoundedProportionalArraySizingStrategy(int minGrow, int maxGrow, float ratio) { + assert minGrow >= 1 : "Min grow must be >= 1."; + assert maxGrow >= minGrow : "Max grow must be >= min grow."; + assert ratio >= 1f : "Growth ratio must be >= 1 (was " + ratio + ")."; + + this.minGrowCount = minGrow; + this.maxGrowCount = maxGrow; + this.growRatio = ratio - 1.0f; + } + + /** + * Grow according to {@link #growRatio}, {@link #minGrowCount} and {@link #maxGrowCount}. + * + * @param currentBufferLength The current length of the buffer. + * @param elementsCount The number of elements stored in the buffer. + * @param expectedAdditions The number of expected additions to the buffer. + * @return New buffer size. + */ + public int grow(int currentBufferLength, int elementsCount, int expectedAdditions) { + long growBy = (long) ((long) currentBufferLength * growRatio); + growBy = Math.max(growBy, minGrowCount); + growBy = Math.min(growBy, maxGrowCount); + long growTo = Math.min(MAX_ARRAY_LENGTH, growBy + currentBufferLength); + long newSize = Math.max((long) elementsCount + expectedAdditions, growTo); + + if (newSize > MAX_ARRAY_LENGTH) { + throw new BufferAllocationException( + "Java array size exceeded (current length: %d, elements: %d, expected additions: %d)", + currentBufferLength, elementsCount, expectedAdditions); + } + + return (int) newSize; + } + + @Override + public long ramBytesAllocated() { + // int: minGrowCount, maxGrowCount + // float: growRatio + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + Integer.BYTES * 2 + Float.BYTES; + } + + @Override + public long ramBytesUsed() { + return ramBytesAllocated(); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/BufferAllocationException.java b/src/main/java/com/carrotsearch/hppc/BufferAllocationException.java new file mode 100755 index 00000000..f09ef3c8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/BufferAllocationException.java @@ -0,0 +1,41 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc; + +import java.util.IllegalFormatException; +import java.util.Locale; + +public class BufferAllocationException extends RuntimeException { + public BufferAllocationException(String message) { + super(message); + } + + public BufferAllocationException(String message, Object... args) { + this(message, null, args); + } + + public BufferAllocationException(String message, Throwable t, Object... args) { + super(formatMessage(message, t, args), t); + } + + private static String formatMessage(String message, Throwable t, Object... args) { + try { + return String.format(Locale.ROOT, message, args); + } catch (IllegalFormatException e) { + BufferAllocationException substitute = + new BufferAllocationException(message + " [ILLEGAL FORMAT, ARGS SUPPRESSED]"); + if (t != null) { + substitute.addSuppressed(t); + } + substitute.addSuppressed(e); + throw substitute; + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ByteArrayDeque.java b/src/main/java/com/carrotsearch/hppc/ByteArrayDeque.java new file mode 100755 index 00000000..b9c809c1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ByteArrayDeque.java @@ -0,0 +1,776 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; + +import com.carrotsearch.hppc.cursors.ByteCursor; +import com.carrotsearch.hppc.predicates.BytePredicate; +import com.carrotsearch.hppc.procedures.ByteProcedure; +import java.util.*; + +/** An array-backed {@link ByteDeque}. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java") +public class ByteArrayDeque extends AbstractByteCollection + implements ByteDeque, Preallocable, Cloneable, Accountable { + + /** Reuse the same strategy instance. */ + private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = + BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; + + /** Internal array for storing elements of the deque. */ + public byte[] buffer = ByteArrayList.EMPTY_ARRAY; + + /** + * The index of the element at the head of the deque or an arbitrary number equal to tail if the + * deque is empty. + */ + public int head; + + /** The index at which the next element would be added to the tail of the deque. */ + public int tail; + + /** Buffer resizing strategy. */ + protected final ArraySizingStrategy resizer; + + /** New instance with sane defaults. */ + public ByteArrayDeque() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ByteArrayDeque(int expectedElements) { + this(expectedElements, DEFAULT_SIZING_STRATEGY); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public ByteArrayDeque(int expectedElements, ArraySizingStrategy resizer) { + assert resizer != null; + this.resizer = resizer; + ensureCapacity(expectedElements); + } + + /** + * Creates a new deque from elements of another container, appending elements at the end of the + * deque in the iteration order. + */ + public ByteArrayDeque(ByteContainer container) { + this(container.size()); + addLast(container); + } + + /** {@inheritDoc} */ + @Override + public void addFirst(byte e1) { + int h = oneLeft(head, buffer.length); + if (h == tail) { + ensureBufferSpace(1); + h = oneLeft(head, buffer.length); + } + buffer[head = h] = e1; + } + + /** + * Vararg-signature method for adding elements at the front of this deque. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + * + * @param elements The elements to add. + */ + public final void addFirst(byte... elements) { + ensureBufferSpace(elements.length); + for (byte k : elements) { + addFirst(k); + } + } + + /** + * Inserts all elements from the given container to the front of this deque. + * + * @param container The container to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addFirst(ByteContainer container) { + int size = container.size(); + ensureBufferSpace(size); + + for (ByteCursor cursor : container) { + addFirst(cursor.value); + } + + return size; + } + + /** + * Inserts all elements from the given iterable to the front of this deque. + * + * @param iterable The iterable to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addFirst(Iterable iterable) { + int size = 0; + for (ByteCursor cursor : iterable) { + addFirst(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public void addLast(byte e1) { + int t = oneRight(tail, buffer.length); + if (head == t) { + ensureBufferSpace(1); + t = oneRight(tail, buffer.length); + } + buffer[tail] = e1; + tail = t; + } + + /** + * Vararg-signature method for adding elements at the end of this deque. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + * + * @param elements The elements to iterate over. + */ + public final void addLast(byte... elements) { + ensureBufferSpace(1); + for (byte k : elements) { + addLast(k); + } + } + + /** + * Inserts all elements from the given container to the end of this deque. + * + * @param container The container to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addLast(ByteContainer container) { + int size = container.size(); + ensureBufferSpace(size); + + for (ByteCursor cursor : container) { + addLast(cursor.value); + } + + return size; + } + + /** + * Inserts all elements from the given iterable to the end of this deque. + * + * @param iterable The iterable to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addLast(Iterable iterable) { + int size = 0; + for (ByteCursor cursor : iterable) { + addLast(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public byte removeFirst() { + assert size() > 0 : "The deque is empty."; + + final byte result = buffer[head]; + buffer[head] = ((byte) 0); + head = oneRight(head, buffer.length); + return result; + } + + /** {@inheritDoc} */ + @Override + public byte removeLast() { + assert size() > 0 : "The deque is empty."; + + tail = oneLeft(tail, buffer.length); + final byte result = buffer[tail]; + buffer[tail] = ((byte) 0); + return result; + } + + /** {@inheritDoc} */ + @Override + public byte getFirst() { + assert size() > 0 : "The deque is empty."; + + return buffer[head]; + } + + /** {@inheritDoc} */ + @Override + public byte getLast() { + assert size() > 0 : "The deque is empty."; + + return buffer[oneLeft(tail, buffer.length)]; + } + + /** {@inheritDoc} */ + @Override + public int removeFirst(byte e1) { + final int index = bufferIndexOf(e1); + if (index >= 0) removeAtBufferIndex(index); + return index; + } + + /** + * Return the index of the first (counting from head) element equal to e1. The index + * points to the {@link #buffer} array. + * + * @param e1 The element to look for. + * @return Returns the index of the first element equal to e1 or -1 if + * not found. + */ + public int bufferIndexOf(byte e1) { + final int last = tail; + final int bufLen = buffer.length; + for (int i = head; i != last; i = oneRight(i, bufLen)) { + if (((e1) == (buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int removeLast(byte e1) { + final int index = lastBufferIndexOf(e1); + if (index >= 0) { + removeAtBufferIndex(index); + } + return index; + } + + /** + * Return the index of the last (counting from tail) element equal to e1. The index + * points to the {@link #buffer} array. + * + * @param e1 The element to look for. + * @return Returns the index of the first element equal to e1 or -1 if + * not found. + */ + public int lastBufferIndexOf(byte e1) { + final int bufLen = buffer.length; + final int last = oneLeft(head, bufLen); + for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) { + if (((e1) == (buffer[i]))) return i; + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(byte e1) { + int removed = 0; + final int last = tail; + final int bufLen = buffer.length; + int from, to; + for (from = to = head; from != last; from = oneRight(from, bufLen)) { + if (((e1) == (buffer[from]))) { + buffer[from] = ((byte) 0); + removed++; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = ((byte) 0); + } + + to = oneRight(to, bufLen); + } + + tail = to; + return removed; + } + + /** + * Removes the element at index in the internal {#link {@link #buffer} array, + * returning its value. + * + * @param index Index of the element to remove. The index must be located between {@link #head} + * and {@link #tail} in modulo {@link #buffer} arithmetic. + */ + public void removeAtBufferIndex(int index) { + assert (head <= tail ? index >= head && index < tail : index >= head || index < tail) + : "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ")."; + + // Cache fields in locals (hopefully moved to registers). + final byte[] buffer = this.buffer; + final int bufLen = buffer.length; + final int lastIndex = bufLen - 1; + final int head = this.head; + final int tail = this.tail; + + final int leftChunk = Math.abs(index - head) % bufLen; + final int rightChunk = Math.abs(tail - index) % bufLen; + + if (leftChunk < rightChunk) { + if (index >= head) { + System.arraycopy(buffer, head, buffer, head + 1, leftChunk); + } else { + System.arraycopy(buffer, 0, buffer, 1, index); + buffer[0] = buffer[lastIndex]; + System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head); + } + buffer[head] = ((byte) 0); + this.head = oneRight(head, bufLen); + } else { + if (index < tail) { + System.arraycopy(buffer, index + 1, buffer, index, rightChunk); + } else { + System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index); + buffer[lastIndex] = buffer[0]; + System.arraycopy(buffer, 1, buffer, 0, tail); + } + buffer[tail] = ((byte) 0); + this.tail = oneLeft(tail, bufLen); + } + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int size() { + if (head <= tail) return tail - head; + else return (tail - head + buffer.length); + } + + /** + * {@inheritDoc} + * + *

The internal array buffers are not released as a result of this call. + * + * @see #release() + */ + @Override + public void clear() { + if (head < tail) { + Arrays.fill(buffer, head, tail, ((byte) 0)); + } else { + Arrays.fill(buffer, 0, tail, ((byte) 0)); + Arrays.fill(buffer, head, buffer.length, ((byte) 0)); + } + this.head = tail = 0; + } + + /** Release internal buffers of this deque and reallocate with the default buffer. */ + public void release() { + this.head = tail = 0; + buffer = ByteArrayList.EMPTY_ARRAY; + ensureBufferSpace(0); + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + ensureBufferSpace(expectedElements - size()); + } + + /** + * Ensures the internal buffer has enough free slots to store expectedAdditions. + * Increases internal buffer size if needed. + */ + protected void ensureBufferSpace(int expectedAdditions) { + final int bufferLen = buffer.length; + final int elementsCount = size(); + + if (elementsCount + expectedAdditions >= bufferLen) { + final int emptySlot = 1; // deque invariant: always an empty slot. + final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions); + assert newSize >= (elementsCount + expectedAdditions + emptySlot) + : "Resizer failed to" + + " return sensible new size: " + + newSize + + " <= " + + (elementsCount + expectedAdditions); + + try { + final byte[] newBuffer = (new byte[newSize]); + if (bufferLen > 0) { + toArray(newBuffer); + tail = elementsCount; + head = 0; + } + this.buffer = newBuffer; + } catch (OutOfMemoryError e) { + throw new BufferAllocationException( + "Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize); + } + } + } + + /** {@inheritDoc} */ + @Override + public byte[] toArray() { + + final int size = size(); + return toArray((new byte[size])); + } + + /** + * Copies elements of this deque to an array. The content of the target array is + * filled from index 0 (head of the queue) to index size() - 1 (tail of the queue). + * + * @param target The target array must be large enough to hold all elements. + * @return Returns the target argument for chaining. + */ + public byte[] toArray(byte[] target) { + assert target.length >= size() : "Target array must be >= " + size(); + + if (head < tail) { + // The contents is not wrapped around. Just copy. + System.arraycopy(buffer, head, target, 0, size()); + } else if (head > tail) { + // The contents is split. Merge elements from the following indexes: + // [head...buffer.length - 1][0, tail - 1] + final int rightCount = buffer.length - head; + System.arraycopy(buffer, head, target, 0, rightCount); + System.arraycopy(buffer, 0, target, rightCount, tail); + } + + return target; + } + + /** + * Clone this object. The returned clone will reuse the same hash function and array resizing + * strategy. + */ + @Override + public ByteArrayDeque clone() { + try { + + ByteArrayDeque cloned = (ByteArrayDeque) super.clone(); + cloned.buffer = buffer.clone(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Move one index to the left, wrapping around buffer. */ + protected static int oneLeft(int index, int modulus) { + if (index >= 1) { + return index - 1; + } + return modulus - 1; + } + + /** Move one index to the right, wrapping around buffer. */ + protected static int oneRight(int index, int modulus) { + if (index + 1 == modulus) { + return 0; + } + return index + 1; + } + + @Override + public long ramBytesAllocated() { + // int: head, tail + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES * 2 + + resizer.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(buffer); + } + + @Override + public long ramBytesUsed() { + // int: head, tail + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES * 2 + + resizer.ramBytesUsed() + + RamUsageEstimator.shallowUsedSizeOfArray(buffer, size()); + } + + /** An iterator implementation for {@link ObjectArrayDeque#iterator}. */ + private final class ValueIterator extends AbstractIterator { + private final ByteCursor cursor; + private int remaining; + + public ValueIterator() { + cursor = new ByteCursor(); + cursor.index = oneLeft(head, buffer.length); + this.remaining = size(); + } + + @Override + protected ByteCursor fetch() { + if (remaining == 0) { + return done(); + } + + remaining--; + cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)]; + return cursor; + } + } + + /** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */ + private final class DescendingValueIterator extends AbstractIterator { + private final ByteCursor cursor; + private int remaining; + + public DescendingValueIterator() { + cursor = new ByteCursor(); + cursor.index = tail; + this.remaining = size(); + } + + @Override + protected ByteCursor fetch() { + if (remaining == 0) return done(); + + remaining--; + cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)]; + return cursor; + } + } + + /** + * Returns a cursor over the values of this deque (in head to tail order). The iterator is + * implemented as a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in + * the deque's buffer) use the cursor's public fields. An example is shown below. + * + *

+   * for (IntValueCursor c : intDeque) {
+   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator iterator() { + return new ValueIterator(); + } + + /** + * Returns a cursor over the values of this deque (in tail to head order). The iterator is + * implemented as a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in + * the deque's buffer) use the cursor's public fields. An example is shown below. + * + *
+   * for (Iterator<IntCursor> i = intDeque.descendingIterator(); i.hasNext();) {
+   *   final IntCursor c = i.next();
+   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator descendingIterator() { + return new DescendingValueIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + forEach(procedure, head, tail); + return procedure; + } + + /** + * Applies procedure to a slice of the deque, fromIndex, inclusive, to + * toIndex, exclusive. + */ + private void forEach(ByteProcedure procedure, int fromIndex, final int toIndex) { + final byte[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + procedure.apply(buffer[i]); + } + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + int fromIndex = head; + int toIndex = tail; + + final byte[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + if (!predicate.apply(buffer[i])) { + break; + } + } + + return predicate; + } + + /** Applies procedure to all elements of this deque, tail to head. */ + @Override + public T descendingForEach(T procedure) { + descendingForEach(procedure, head, tail); + return procedure; + } + + /** + * Applies procedure to a slice of the deque, toIndex, exclusive, down + * to fromIndex, inclusive. + */ + private void descendingForEach(ByteProcedure procedure, int fromIndex, final int toIndex) { + if (fromIndex == toIndex) return; + + final byte[] buffer = this.buffer; + int i = toIndex; + do { + i = oneLeft(i, buffer.length); + procedure.apply(buffer[i]); + } while (i != fromIndex); + } + + /** {@inheritDoc} */ + @Override + public T descendingForEach(T predicate) { + descendingForEach(predicate, head, tail); + return predicate; + } + + /** + * Applies predicate to a slice of the deque, toIndex, exclusive, down + * to fromIndex, inclusive or until the predicate returns false. + */ + private void descendingForEach(BytePredicate predicate, int fromIndex, final int toIndex) { + if (fromIndex == toIndex) return; + + final byte[] buffer = this.buffer; + int i = toIndex; + do { + i = oneLeft(i, buffer.length); + if (!predicate.apply(buffer[i])) { + break; + } + } while (i != fromIndex); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(BytePredicate predicate) { + final byte[] buffer = this.buffer; + final int last = tail; + final int bufLen = buffer.length; + int removed = 0; + int from, to; + from = to = head; + try { + for (from = to = head; from != last; from = oneRight(from, bufLen)) { + if (predicate.apply(buffer[from])) { + buffer[from] = ((byte) 0); + removed++; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = ((byte) 0); + } + + to = oneRight(to, bufLen); + } + } finally { + // Keep the deque in consistent state even if the predicate throws an exception. + for (; from != last; from = oneRight(from, bufLen)) { + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = ((byte) 0); + } + + to = oneRight(to, bufLen); + } + tail = to; + } + + return removed; + } + + /** {@inheritDoc} */ + @Override + public boolean contains(byte e) { + int fromIndex = head; + int toIndex = tail; + + final byte[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + if (((e) == (buffer[i]))) { + return true; + } + } + + return false; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 1; + int fromIndex = head; + int toIndex = tail; + + final byte[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + h = 31 * h + BitMixer.mix(this.buffer[i]); + } + return h; + } + + /** + * Returns true only if the other object is an instance of the same class and with + * the same elements. + */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Compare order-aligned elements against another {@link ByteDeque}. */ + protected boolean equalElements(ByteArrayDeque other) { + int max = size(); + if (other.size() != max) { + return false; + } + + Iterator i1 = this.iterator(); + Iterator i2 = other.iterator(); + + while (i1.hasNext() && i2.hasNext()) { + if (!((i1.next().value) == (i2.next().value))) { + return false; + } + } + + return !i1.hasNext() && !i2.hasNext(); + } + + /** Create a new deque by pushing a variable number of arguments to the end of it. */ + public static ByteArrayDeque from(byte... elements) { + final ByteArrayDeque coll = new ByteArrayDeque(elements.length); + coll.addLast(elements); + return coll; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ByteArrayList.java b/src/main/java/com/carrotsearch/hppc/ByteArrayList.java new file mode 100755 index 00000000..836c6b9d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ByteArrayList.java @@ -0,0 +1,579 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.BytePredicate; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** An array-backed list of bytes. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java") +public class ByteArrayList extends AbstractByteCollection + implements ByteIndexedContainer, Preallocable, Cloneable, Accountable { + /** An immutable empty buffer (array). */ + public static final byte[] EMPTY_ARRAY = new byte[0]; + + ; + + /** Reuse the same strategy instance. */ + private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = + BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; + + /** + * Internal array for storing the list. The array may be larger than the current size ({@link + * #size()}). + */ + public byte[] buffer = EMPTY_ARRAY; + + /** Current number of elements stored in {@link #buffer}. */ + public int elementsCount; + + /** Buffer resizing strategy. */ + protected final ArraySizingStrategy resizer; + + /** New instance with sane defaults. */ + public ByteArrayList() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ByteArrayList(int expectedElements) { + this(expectedElements, DEFAULT_SIZING_STRATEGY); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public ByteArrayList(int expectedElements, ArraySizingStrategy resizer) { + assert resizer != null; + this.resizer = resizer; + buffer = Arrays.copyOf(buffer, expectedElements); + } + + /** Creates a new list from the elements of another container in its iteration order. */ + public ByteArrayList(ByteContainer container) { + this(container.size()); + addAll(container); + } + + /** {@inheritDoc} */ + @Override + public void add(byte e1) { + ensureBufferSpace(1); + buffer[elementsCount++] = e1; + } + + /** + * Appends two elements at the end of the list. To add more than two elements, use add + * (vararg-version) or access the buffer directly (tight loop). + */ + public void add(byte e1, byte e2) { + ensureBufferSpace(2); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + } + + /** Add all elements from a range of given array to the list. */ + public void add(byte[] elements, int start, int length) { + assert length >= 0 : "Length must be >= 0"; + + ensureBufferSpace(length); + System.arraycopy(elements, start, buffer, elementsCount, length); + elementsCount += length; + } + + /** + * Vararg-signature method for adding elements at the end of the list. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + */ + public final void add(byte... elements) { + add(elements, 0, elements.length); + } + + /** Adds all elements from another container. */ + public int addAll(ByteContainer container) { + final int size = container.size(); + ensureBufferSpace(size); + + for (ByteCursor cursor : container) { + add(cursor.value); + } + + return size; + } + + /** Adds all elements from another iterable. */ + public int addAll(Iterable iterable) { + int size = 0; + for (ByteCursor cursor : iterable) { + add(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public void insert(int index, byte e1) { + assert (index >= 0 && index <= size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + "]."; + + ensureBufferSpace(1); + System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index); + buffer[index] = e1; + elementsCount++; + } + + /** {@inheritDoc} */ + @Override + public byte get(int index) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + return buffer[index]; + } + + /** {@inheritDoc} */ + @Override + public byte set(int index, byte e1) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + final byte v = buffer[index]; + buffer[index] = e1; + return v; + } + + /** {@inheritDoc} */ + @Override + public byte removeAt(int index) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + final byte v = buffer[index]; + System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index); + + return v; + } + + /** {@inheritDoc} */ + @Override + public byte removeLast() { + assert elementsCount > 0; + + final byte v = buffer[--elementsCount]; + + return v; + } + + /** {@inheritDoc} */ + @Override + public void removeRange(int fromIndex, int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex); + final int count = toIndex - fromIndex; + elementsCount -= count; + } + + /** {@inheritDoc} */ + @Override + public boolean removeElement(byte e1) { + return removeFirst(e1) != -1; + } + + /** {@inheritDoc} */ + @Override + public int removeFirst(byte e1) { + final int index = indexOf(e1); + if (index >= 0) removeAt(index); + return index; + } + + /** {@inheritDoc} */ + @Override + public int removeLast(byte e1) { + final int index = lastIndexOf(e1); + if (index >= 0) removeAt(index); + return index; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(byte e1) { + int to = 0; + for (int from = 0; from < elementsCount; from++) { + if (((e1) == (buffer[from]))) { + continue; + } + if (to != from) { + buffer[to] = buffer[from]; + } + to++; + } + final int deleted = elementsCount - to; + this.elementsCount = to; + + return deleted; + } + + /** {@inheritDoc} */ + @Override + public boolean contains(byte e1) { + return indexOf(e1) >= 0; + } + + /** {@inheritDoc} */ + @Override + public int indexOf(byte e1) { + for (int i = 0; i < elementsCount; i++) { + if (((e1) == (buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int lastIndexOf(byte e1) { + for (int i = elementsCount - 1; i >= 0; i--) { + if (((e1) == (buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return elementsCount == 0; + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + final int bufferLen = (buffer == null ? 0 : buffer.length); + if (expectedElements > bufferLen) { + ensureBufferSpace(expectedElements - size()); + } + } + + /** + * Ensures the internal buffer has enough free slots to store expectedAdditions. + * Increases internal buffer size if needed. + */ + protected void ensureBufferSpace(int expectedAdditions) { + final int bufferLen = (buffer == null ? 0 : buffer.length); + if (elementsCount + expectedAdditions > bufferLen) { + final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions); + assert newSize >= elementsCount + expectedAdditions + : "Resizer failed to" + + " return sensible new size: " + + newSize + + " <= " + + (elementsCount + expectedAdditions); + + this.buffer = Arrays.copyOf(buffer, newSize); + } + } + + /** + * Truncate or expand the list to the new size. If the list is truncated, the buffer will not be + * reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated + * values will be reset to the default value (zero). If the list is expanded, the elements beyond + * the current size are initialized with JVM-defaults (zero or null values). + */ + public void resize(int newSize) { + if (newSize <= buffer.length) { + if (newSize < elementsCount) { + Arrays.fill(buffer, newSize, elementsCount, ((byte) 0)); + } else { + Arrays.fill(buffer, elementsCount, newSize, ((byte) 0)); + } + } else { + ensureCapacity(newSize); + } + this.elementsCount = newSize; + } + + /** {@inheritDoc} */ + @Override + public int size() { + return elementsCount; + } + + /** Trim the internal buffer to the current size. */ + public void trimToSize() { + if (size() != this.buffer.length) { + this.buffer = toArray(); + } + } + + /** + * Sets the number of stored elements to zero. Releases and initializes the internal storage array + * to default values. To clear the list without cleaning the buffer, simply set the {@link + * #elementsCount} field to zero. + */ + @Override + public void clear() { + Arrays.fill(buffer, 0, elementsCount, ((byte) 0)); + this.elementsCount = 0; + } + + /** Sets the number of stored elements to zero and releases the internal storage array. */ + @Override + public void release() { + this.buffer = EMPTY_ARRAY; + this.elementsCount = 0; + } + + /** + * {@inheritDoc} + * + *

The returned array is sized to match exactly the number of elements of the stack. + */ + @Override + public byte[] toArray() { + + return Arrays.copyOf(buffer, elementsCount); + } + + /** {@inheritDoc} */ + @Override + public ByteIndexedContainer sort() { + Arrays.sort(buffer, 0, elementsCount); + return this; + } + + /** {@inheritDoc} */ + @Override + public ByteIndexedContainer reverse() { + for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) { + byte tmp = buffer[i]; + buffer[i] = buffer[j]; + buffer[j] = tmp; + } + return this; + } + + /** + * Clone this object. The returned clone will reuse the same hash function and array resizing + * strategy. + */ + @Override + public ByteArrayList clone() { + try { + + final ByteArrayList cloned = (ByteArrayList) super.clone(); + cloned.buffer = buffer.clone(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 1, max = elementsCount; + for (int i = 0; i < max; i++) { + h = 31 * h + BitMixer.mix(this.buffer[i]); + } + return h; + } + + /** + * Returns true only if the other object is an instance of the same class and with + * the same elements. + */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Compare index-aligned elements against another {@link ByteIndexedContainer}. */ + protected boolean equalElements(ByteArrayList other) { + int max = size(); + if (other.size() != max) { + return false; + } + + for (int i = 0; i < max; i++) { + if (!((get(i)) == (other.get(i)))) { + return false; + } + } + + return true; + } + + @Override + public long ramBytesAllocated() { + // int: elementsCount + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES + + resizer.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(buffer); + } + + @Override + public long ramBytesUsed() { + // int: elementsCount + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES + + resizer.ramBytesUsed() + + RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount); + } + + /** An iterator implementation for {@link ByteArrayList#iterator}. */ + static final class ValueIterator extends AbstractIterator { + private final ByteCursor cursor; + + private final byte[] buffer; + private final int size; + + public ValueIterator(byte[] buffer, int size) { + this.cursor = new ByteCursor(); + this.cursor.index = -1; + this.size = size; + this.buffer = buffer; + } + + @Override + protected ByteCursor fetch() { + if (cursor.index + 1 == size) return done(); + + cursor.value = buffer[++cursor.index]; + return cursor; + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new ValueIterator(buffer, size()); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + return forEach(procedure, 0, size()); + } + + /** + * Applies procedure to a slice of the list, fromIndex, inclusive, to + * toIndex, exclusive. + */ + public T forEach(T procedure, int fromIndex, final int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + final byte[] buffer = this.buffer; + for (int i = fromIndex; i < toIndex; i++) { + procedure.apply(buffer[i]); + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(BytePredicate predicate) { + final byte[] buffer = this.buffer; + final int elementsCount = this.elementsCount; + int to = 0; + int from = 0; + try { + for (; from < elementsCount; from++) { + if (predicate.apply(buffer[from])) { + buffer[from] = ((byte) 0); + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = ((byte) 0); + } + to++; + } + } finally { + // Keep the list in a consistent state, even if the predicate throws an exception. + for (; from < elementsCount; from++) { + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = ((byte) 0); + } + to++; + } + + this.elementsCount = to; + } + + return elementsCount - to; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + return forEach(predicate, 0, size()); + } + + /** + * Applies predicate to a slice of the list, fromIndex, inclusive, to + * toIndex, exclusive, or until predicate returns false. + */ + public T forEach(T predicate, int fromIndex, final int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + final byte[] buffer = this.buffer; + for (int i = fromIndex; i < toIndex; i++) { + if (!predicate.apply(buffer[i])) break; + } + + return predicate; + } + + /** + * Create a list from a variable number of arguments or an array of byte. The + * elements are copied from the argument to the internal buffer. + */ + public static ByteArrayList from(byte... elements) { + final ByteArrayList list = new ByteArrayList(elements.length); + list.add(elements); + return list; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ByteBufferVisualizer.java b/src/main/java/com/carrotsearch/hppc/ByteBufferVisualizer.java new file mode 100755 index 00000000..0a39142a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ByteBufferVisualizer.java @@ -0,0 +1,33 @@ +package com.carrotsearch.hppc; + +/** + * Reused buffer visualization routines. + * + * @see ByteSet#visualizeKeyDistribution(int) + * @see ByteVTypeMap#visualizeKeyDistribution(int) + */ +class ByteBufferVisualizer { + static String visualizeKeyDistribution(byte[] buffer, int max, int characters) { + final StringBuilder b = new StringBuilder(); + final char[] chars = ".123456789X".toCharArray(); + for (int i = 1, start = -1; i <= characters; i++) { + int end = (int) ((long) i * max / characters); + + if (start + 1 <= end) { + int taken = 0; + int slots = 0; + for (int slot = start + 1; slot <= end; slot++, slots++) { + if (!((buffer[slot]) == 0)) { + taken++; + } + } + b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]); + start = end; + } + } + while (b.length() < characters) { + b.append(' '); + } + return b.toString(); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ByteCollection.java b/src/main/java/com/carrotsearch/hppc/ByteCollection.java new file mode 100755 index 00000000..2e89418e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ByteCollection.java @@ -0,0 +1,64 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.predicates.BytePredicate; + +/** + * A collection allows basic, efficient operations on sets of elements (difference and + * intersection). + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java") +public interface ByteCollection extends ByteContainer { + /** + * Removes all occurrences of e from this collection. + * + * @param e Element to be removed from this collection, if present. + * @return The number of removed elements as a result of this call. + */ + public int removeAll(byte e); + + /** + * Removes all elements in this collection that are present in c. + * + * @return Returns the number of removed elements. + */ + public int removeAll(ByteLookupContainer c); + + /** + * Removes all elements in this collection for which the given predicate returns true + * . + * + * @return Returns the number of removed elements. + */ + public int removeAll(BytePredicate predicate); + + /** + * Keeps all elements in this collection that are present in c. Runs in time + * proportional to the number of elements in this collection. Equivalent of sets intersection. + * + * @return Returns the number of removed elements. + */ + public int retainAll(ByteLookupContainer c); + + /** + * Keeps all elements in this collection for which the given predicate returns true. + * + * @return Returns the number of removed elements. + */ + public int retainAll(BytePredicate predicate); + + /** + * Removes all elements from this collection. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ByteContainer.java b/src/main/java/com/carrotsearch/hppc/ByteContainer.java new file mode 100755 index 00000000..19edc86b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ByteContainer.java @@ -0,0 +1,76 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ByteCursor; +import com.carrotsearch.hppc.predicates.BytePredicate; +import com.carrotsearch.hppc.procedures.ByteProcedure; +import java.util.Iterator; + +/** A generic container holding bytes. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java") +public interface ByteContainer extends Iterable { + /** + * Returns an iterator to a cursor traversing the collection. The order of traversal is not + * defined. More than one cursor may be active at a time. The behavior of iterators is undefined + * if structural changes are made to the underlying collection. + * + *

The iterator is implemented as a cursor and it returns the same cursor instance on + * every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current + * list's value (or index in the list) use the cursor's public fields. An example is shown below. + * + *

+   * for (ByteCursor<byte> c : container) {
+   *   System.out.println("index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator iterator(); + + /** + * Lookup a given element in the container. This operation has no speed guarantees (may be linear + * with respect to the size of this container). + * + * @return Returns true if this container has an element equal to e. + */ + public boolean contains(byte e); + + /** + * Return the current number of elements in this container. The time for calculating the + * container's size may take O(n) time, although implementing classes should try to + * maintain the current size and return in constant time. + */ + public int size(); + + /** Shortcut for size() == 0. */ + public boolean isEmpty(); + + /** + * Copies all elements of this container to an array. + * + *

The returned array is always a copy, regardless of the storage used by the container. + */ + public byte[] toArray(); + + /** + * Applies a procedure to all container elements. Returns the argument (any subclass + * of {@link ByteProcedure}. This lets the caller to call methods of the argument by chaining the + * call (even if the argument is an anonymous type) to retrieve computed values, for example + * (IntContainer): + * + *

+   * int count = container.forEach(new IntProcedure() {
+   *   int count; // this is a field declaration in an anonymous class.
+   *
+   *   public void apply(int value) {
+   *     count++;
+   *   }
+   * }).count;
+   * 
+ */ + public T forEach(T procedure); + + /** + * Applies a predicate to container elements as long, as the predicate returns + * true. The iteration is interrupted otherwise. + */ + public T forEach(T predicate); +} diff --git a/src/main/java/com/carrotsearch/hppc/ByteDeque.java b/src/main/java/com/carrotsearch/hppc/ByteDeque.java new file mode 100755 index 00000000..3b8dd7fe --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ByteDeque.java @@ -0,0 +1,77 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ByteCursor; +import com.carrotsearch.hppc.predicates.BytePredicate; +import com.carrotsearch.hppc.procedures.ByteProcedure; +import java.util.Deque; +import java.util.Iterator; + +/** + * A linear collection that supports element insertion and removal at both ends. + * + * @see Deque + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java") +public interface ByteDeque extends ByteCollection { + /** + * Removes the first element that equals e. + * + * @return The deleted element's index or -1 if the element was not found. + */ + public int removeFirst(byte e); + + /** + * Removes the last element that equals e. + * + * @return The deleted element's index or -1 if the element was not found. + */ + public int removeLast(byte e); + + /** Inserts the specified element at the front of this deque. */ + public void addFirst(byte e); + + /** Inserts the specified element at the end of this deque. */ + public void addLast(byte e); + + /** + * Retrieves and removes the first element of this deque. + * + * @return the head (first) element of this deque. + */ + public byte removeFirst(); + + /** + * Retrieves and removes the last element of this deque. + * + * @return the tail of this deque. + */ + public byte removeLast(); + + /** + * Retrieves the first element of this deque but does not remove it. + * + * @return the head of this deque. + */ + public byte getFirst(); + + /** + * Retrieves the last element of this deque but does not remove it. + * + * @return the head of this deque. + */ + public byte getLast(); + + /** + * @return An iterator over elements in this deque in tail-to-head order. + */ + public Iterator descendingIterator(); + + /** Applies a procedure to all elements in tail-to-head order. */ + public T descendingForEach(T procedure); + + /** + * Applies a predicate to container elements as long, as the predicate returns + * true. The iteration is interrupted otherwise. + */ + public T descendingForEach(T predicate); +} diff --git a/src/main/java/com/carrotsearch/hppc/ByteIndexedContainer.java b/src/main/java/com/carrotsearch/hppc/ByteIndexedContainer.java new file mode 100755 index 00000000..f70fb895 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ByteIndexedContainer.java @@ -0,0 +1,91 @@ +package com.carrotsearch.hppc; + +import java.util.RandomAccess; + +/** + * An indexed container provides random access to elements based on an index. Indexes + * are zero-based. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeIndexedContainer.java") +public interface ByteIndexedContainer extends ByteCollection, RandomAccess { + /** + * Removes the first element that equals e1, returning whether an element has been + * removed. + */ + public boolean removeElement(byte e1); + + /** + * Removes the first element that equals e1, returning its deleted position or + * -1 if the element was not found. + */ + public int removeFirst(byte e1); + + /** + * Removes the last element that equals e1, returning its deleted position or + * -1 if the element was not found. + */ + public int removeLast(byte e1); + + /** + * Returns the index of the first occurrence of the specified element in this list, or -1 if this + * list does not contain the element. + */ + public int indexOf(byte e1); + + /** + * Returns the index of the last occurrence of the specified element in this list, or -1 if this + * list does not contain the element. + */ + public int lastIndexOf(byte e1); + + /** Adds an element to the end of this container (the last index is incremented by one). */ + public void add(byte e1); + + /** + * Inserts the specified element at the specified position in this list. + * + * @param index The index at which the element should be inserted, shifting any existing and + * subsequent elements to the right. + */ + public void insert(int index, byte e1); + + /** + * Replaces the element at the specified position in this list with the specified element. + * + * @return Returns the previous value in the list. + */ + public byte set(int index, byte e1); + + /** + * @return Returns the element at index index from the list. + */ + public byte get(int index); + + /** + * Removes the element at the specified position in this container and returns it. + * + * @see #removeFirst + * @see #removeLast + * @see #removeAll + */ + public byte removeAt(int index); + + /** Removes and returns the last element of this container. This container must not be empty. */ + public byte removeLast(); + + /** + * Removes from this container all of the elements with indexes between fromIndex, + * inclusive, and toIndex, exclusive. + */ + public void removeRange(int fromIndex, int toIndex); + + /** Returns this container elements as a stream. */ + + /** Sorts the elements in this container and returns this container. */ + public ByteIndexedContainer sort(); + + /** Reverses the elements in this container and returns this container. */ + public ByteIndexedContainer reverse(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ByteLookupContainer.java b/src/main/java/com/carrotsearch/hppc/ByteLookupContainer.java new file mode 100755 index 00000000..ac41bc0b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ByteLookupContainer.java @@ -0,0 +1,12 @@ +package com.carrotsearch.hppc; + +/** + * Marker interface for containers that can check if they contain a given object in at least time + * O(log n) and ideally in amortized constant time O(1). + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeLookupContainer.java") +public interface ByteLookupContainer extends ByteContainer { + public boolean contains(byte e); +} diff --git a/src/main/java/com/carrotsearch/hppc/ByteStack.java b/src/main/java/com/carrotsearch/hppc/ByteStack.java new file mode 100755 index 00000000..0cf32432 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ByteStack.java @@ -0,0 +1,137 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ByteCursor; + +/** + * A subclass of {@link ByteArrayList} adding stack-related utility methods. The top of the stack is + * at the {@link #size()} - 1 element. + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java") +public class ByteStack extends ByteArrayList { + /** New instance with sane defaults. */ + public ByteStack() { + super(); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ByteStack(int expectedElements) { + super(expectedElements); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public ByteStack(int expectedElements, ArraySizingStrategy resizer) { + super(expectedElements, resizer); + } + + /** Create a stack by pushing all elements of another container to it. */ + public ByteStack(ByteContainer container) { + super(container); + } + + /** Adds one byte to the stack. */ + public void push(byte e1) { + ensureBufferSpace(1); + buffer[elementsCount++] = e1; + } + + /** Adds two bytes to the stack. */ + public void push(byte e1, byte e2) { + ensureBufferSpace(2); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + } + + /** Adds three bytes to the stack. */ + public void push(byte e1, byte e2, byte e3) { + ensureBufferSpace(3); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + buffer[elementsCount++] = e3; + } + + /** Adds four bytes to the stack. */ + public void push(byte e1, byte e2, byte e3, byte e4) { + ensureBufferSpace(4); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + buffer[elementsCount++] = e3; + buffer[elementsCount++] = e4; + } + + /** Add a range of array elements to the stack. */ + public void push(byte[] elements, int start, int len) { + assert start >= 0 && len >= 0; + + ensureBufferSpace(len); + System.arraycopy(elements, start, buffer, elementsCount, len); + elementsCount += len; + } + + /** + * Vararg-signature method for pushing elements at the top of the stack. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + */ + public final void push(byte... elements) { + push(elements, 0, elements.length); + } + + /** Pushes all elements from another container to the top of the stack. */ + public int pushAll(ByteContainer container) { + return addAll(container); + } + + /** Pushes all elements from another iterable to the top of the stack. */ + public int pushAll(Iterable iterable) { + return addAll(iterable); + } + + /** Discard an arbitrary number of elements from the top of the stack. */ + public void discard(int count) { + assert elementsCount >= count; + + elementsCount -= count; + } + + /** Discard the top element from the stack. */ + public void discard() { + assert elementsCount > 0; + + elementsCount--; + } + + /** Remove the top element from the stack and return it. */ + public byte pop() { + return removeLast(); + } + + /** Peek at the top element on the stack. */ + public byte peek() { + assert elementsCount > 0; + return buffer[elementsCount - 1]; + } + + /** Create a stack by pushing a variable number of arguments to it. */ + public static ByteStack from(byte... elements) { + final ByteStack stack = new ByteStack(elements.length); + stack.push(elements); + return stack; + } + + /** {@inheritDoc} */ + @Override + public ByteStack clone() { + return (ByteStack) super.clone(); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/CharArrayDeque.java b/src/main/java/com/carrotsearch/hppc/CharArrayDeque.java new file mode 100755 index 00000000..e8aeb6a4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharArrayDeque.java @@ -0,0 +1,776 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; + +import com.carrotsearch.hppc.cursors.CharCursor; +import com.carrotsearch.hppc.predicates.CharPredicate; +import com.carrotsearch.hppc.procedures.CharProcedure; +import java.util.*; + +/** An array-backed {@link CharDeque}. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java") +public class CharArrayDeque extends AbstractCharCollection + implements CharDeque, Preallocable, Cloneable, Accountable { + + /** Reuse the same strategy instance. */ + private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = + BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; + + /** Internal array for storing elements of the deque. */ + public char[] buffer = CharArrayList.EMPTY_ARRAY; + + /** + * The index of the element at the head of the deque or an arbitrary number equal to tail if the + * deque is empty. + */ + public int head; + + /** The index at which the next element would be added to the tail of the deque. */ + public int tail; + + /** Buffer resizing strategy. */ + protected final ArraySizingStrategy resizer; + + /** New instance with sane defaults. */ + public CharArrayDeque() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public CharArrayDeque(int expectedElements) { + this(expectedElements, DEFAULT_SIZING_STRATEGY); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public CharArrayDeque(int expectedElements, ArraySizingStrategy resizer) { + assert resizer != null; + this.resizer = resizer; + ensureCapacity(expectedElements); + } + + /** + * Creates a new deque from elements of another container, appending elements at the end of the + * deque in the iteration order. + */ + public CharArrayDeque(CharContainer container) { + this(container.size()); + addLast(container); + } + + /** {@inheritDoc} */ + @Override + public void addFirst(char e1) { + int h = oneLeft(head, buffer.length); + if (h == tail) { + ensureBufferSpace(1); + h = oneLeft(head, buffer.length); + } + buffer[head = h] = e1; + } + + /** + * Vararg-signature method for adding elements at the front of this deque. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + * + * @param elements The elements to add. + */ + public final void addFirst(char... elements) { + ensureBufferSpace(elements.length); + for (char k : elements) { + addFirst(k); + } + } + + /** + * Inserts all elements from the given container to the front of this deque. + * + * @param container The container to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addFirst(CharContainer container) { + int size = container.size(); + ensureBufferSpace(size); + + for (CharCursor cursor : container) { + addFirst(cursor.value); + } + + return size; + } + + /** + * Inserts all elements from the given iterable to the front of this deque. + * + * @param iterable The iterable to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addFirst(Iterable iterable) { + int size = 0; + for (CharCursor cursor : iterable) { + addFirst(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public void addLast(char e1) { + int t = oneRight(tail, buffer.length); + if (head == t) { + ensureBufferSpace(1); + t = oneRight(tail, buffer.length); + } + buffer[tail] = e1; + tail = t; + } + + /** + * Vararg-signature method for adding elements at the end of this deque. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + * + * @param elements The elements to iterate over. + */ + public final void addLast(char... elements) { + ensureBufferSpace(1); + for (char k : elements) { + addLast(k); + } + } + + /** + * Inserts all elements from the given container to the end of this deque. + * + * @param container The container to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addLast(CharContainer container) { + int size = container.size(); + ensureBufferSpace(size); + + for (CharCursor cursor : container) { + addLast(cursor.value); + } + + return size; + } + + /** + * Inserts all elements from the given iterable to the end of this deque. + * + * @param iterable The iterable to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addLast(Iterable iterable) { + int size = 0; + for (CharCursor cursor : iterable) { + addLast(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public char removeFirst() { + assert size() > 0 : "The deque is empty."; + + final char result = buffer[head]; + buffer[head] = ((char) 0); + head = oneRight(head, buffer.length); + return result; + } + + /** {@inheritDoc} */ + @Override + public char removeLast() { + assert size() > 0 : "The deque is empty."; + + tail = oneLeft(tail, buffer.length); + final char result = buffer[tail]; + buffer[tail] = ((char) 0); + return result; + } + + /** {@inheritDoc} */ + @Override + public char getFirst() { + assert size() > 0 : "The deque is empty."; + + return buffer[head]; + } + + /** {@inheritDoc} */ + @Override + public char getLast() { + assert size() > 0 : "The deque is empty."; + + return buffer[oneLeft(tail, buffer.length)]; + } + + /** {@inheritDoc} */ + @Override + public int removeFirst(char e1) { + final int index = bufferIndexOf(e1); + if (index >= 0) removeAtBufferIndex(index); + return index; + } + + /** + * Return the index of the first (counting from head) element equal to e1. The index + * points to the {@link #buffer} array. + * + * @param e1 The element to look for. + * @return Returns the index of the first element equal to e1 or -1 if + * not found. + */ + public int bufferIndexOf(char e1) { + final int last = tail; + final int bufLen = buffer.length; + for (int i = head; i != last; i = oneRight(i, bufLen)) { + if (((e1) == (buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int removeLast(char e1) { + final int index = lastBufferIndexOf(e1); + if (index >= 0) { + removeAtBufferIndex(index); + } + return index; + } + + /** + * Return the index of the last (counting from tail) element equal to e1. The index + * points to the {@link #buffer} array. + * + * @param e1 The element to look for. + * @return Returns the index of the first element equal to e1 or -1 if + * not found. + */ + public int lastBufferIndexOf(char e1) { + final int bufLen = buffer.length; + final int last = oneLeft(head, bufLen); + for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) { + if (((e1) == (buffer[i]))) return i; + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(char e1) { + int removed = 0; + final int last = tail; + final int bufLen = buffer.length; + int from, to; + for (from = to = head; from != last; from = oneRight(from, bufLen)) { + if (((e1) == (buffer[from]))) { + buffer[from] = ((char) 0); + removed++; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = ((char) 0); + } + + to = oneRight(to, bufLen); + } + + tail = to; + return removed; + } + + /** + * Removes the element at index in the internal {#link {@link #buffer} array, + * returning its value. + * + * @param index Index of the element to remove. The index must be located between {@link #head} + * and {@link #tail} in modulo {@link #buffer} arithmetic. + */ + public void removeAtBufferIndex(int index) { + assert (head <= tail ? index >= head && index < tail : index >= head || index < tail) + : "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ")."; + + // Cache fields in locals (hopefully moved to registers). + final char[] buffer = this.buffer; + final int bufLen = buffer.length; + final int lastIndex = bufLen - 1; + final int head = this.head; + final int tail = this.tail; + + final int leftChunk = Math.abs(index - head) % bufLen; + final int rightChunk = Math.abs(tail - index) % bufLen; + + if (leftChunk < rightChunk) { + if (index >= head) { + System.arraycopy(buffer, head, buffer, head + 1, leftChunk); + } else { + System.arraycopy(buffer, 0, buffer, 1, index); + buffer[0] = buffer[lastIndex]; + System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head); + } + buffer[head] = ((char) 0); + this.head = oneRight(head, bufLen); + } else { + if (index < tail) { + System.arraycopy(buffer, index + 1, buffer, index, rightChunk); + } else { + System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index); + buffer[lastIndex] = buffer[0]; + System.arraycopy(buffer, 1, buffer, 0, tail); + } + buffer[tail] = ((char) 0); + this.tail = oneLeft(tail, bufLen); + } + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int size() { + if (head <= tail) return tail - head; + else return (tail - head + buffer.length); + } + + /** + * {@inheritDoc} + * + *

The internal array buffers are not released as a result of this call. + * + * @see #release() + */ + @Override + public void clear() { + if (head < tail) { + Arrays.fill(buffer, head, tail, ((char) 0)); + } else { + Arrays.fill(buffer, 0, tail, ((char) 0)); + Arrays.fill(buffer, head, buffer.length, ((char) 0)); + } + this.head = tail = 0; + } + + /** Release internal buffers of this deque and reallocate with the default buffer. */ + public void release() { + this.head = tail = 0; + buffer = CharArrayList.EMPTY_ARRAY; + ensureBufferSpace(0); + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + ensureBufferSpace(expectedElements - size()); + } + + /** + * Ensures the internal buffer has enough free slots to store expectedAdditions. + * Increases internal buffer size if needed. + */ + protected void ensureBufferSpace(int expectedAdditions) { + final int bufferLen = buffer.length; + final int elementsCount = size(); + + if (elementsCount + expectedAdditions >= bufferLen) { + final int emptySlot = 1; // deque invariant: always an empty slot. + final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions); + assert newSize >= (elementsCount + expectedAdditions + emptySlot) + : "Resizer failed to" + + " return sensible new size: " + + newSize + + " <= " + + (elementsCount + expectedAdditions); + + try { + final char[] newBuffer = (new char[newSize]); + if (bufferLen > 0) { + toArray(newBuffer); + tail = elementsCount; + head = 0; + } + this.buffer = newBuffer; + } catch (OutOfMemoryError e) { + throw new BufferAllocationException( + "Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize); + } + } + } + + /** {@inheritDoc} */ + @Override + public char[] toArray() { + + final int size = size(); + return toArray((new char[size])); + } + + /** + * Copies elements of this deque to an array. The content of the target array is + * filled from index 0 (head of the queue) to index size() - 1 (tail of the queue). + * + * @param target The target array must be large enough to hold all elements. + * @return Returns the target argument for chaining. + */ + public char[] toArray(char[] target) { + assert target.length >= size() : "Target array must be >= " + size(); + + if (head < tail) { + // The contents is not wrapped around. Just copy. + System.arraycopy(buffer, head, target, 0, size()); + } else if (head > tail) { + // The contents is split. Merge elements from the following indexes: + // [head...buffer.length - 1][0, tail - 1] + final int rightCount = buffer.length - head; + System.arraycopy(buffer, head, target, 0, rightCount); + System.arraycopy(buffer, 0, target, rightCount, tail); + } + + return target; + } + + /** + * Clone this object. The returned clone will reuse the same hash function and array resizing + * strategy. + */ + @Override + public CharArrayDeque clone() { + try { + + CharArrayDeque cloned = (CharArrayDeque) super.clone(); + cloned.buffer = buffer.clone(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Move one index to the left, wrapping around buffer. */ + protected static int oneLeft(int index, int modulus) { + if (index >= 1) { + return index - 1; + } + return modulus - 1; + } + + /** Move one index to the right, wrapping around buffer. */ + protected static int oneRight(int index, int modulus) { + if (index + 1 == modulus) { + return 0; + } + return index + 1; + } + + @Override + public long ramBytesAllocated() { + // int: head, tail + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES * 2 + + resizer.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(buffer); + } + + @Override + public long ramBytesUsed() { + // int: head, tail + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES * 2 + + resizer.ramBytesUsed() + + RamUsageEstimator.shallowUsedSizeOfArray(buffer, size()); + } + + /** An iterator implementation for {@link ObjectArrayDeque#iterator}. */ + private final class ValueIterator extends AbstractIterator { + private final CharCursor cursor; + private int remaining; + + public ValueIterator() { + cursor = new CharCursor(); + cursor.index = oneLeft(head, buffer.length); + this.remaining = size(); + } + + @Override + protected CharCursor fetch() { + if (remaining == 0) { + return done(); + } + + remaining--; + cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)]; + return cursor; + } + } + + /** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */ + private final class DescendingValueIterator extends AbstractIterator { + private final CharCursor cursor; + private int remaining; + + public DescendingValueIterator() { + cursor = new CharCursor(); + cursor.index = tail; + this.remaining = size(); + } + + @Override + protected CharCursor fetch() { + if (remaining == 0) return done(); + + remaining--; + cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)]; + return cursor; + } + } + + /** + * Returns a cursor over the values of this deque (in head to tail order). The iterator is + * implemented as a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in + * the deque's buffer) use the cursor's public fields. An example is shown below. + * + *

+   * for (IntValueCursor c : intDeque) {
+   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator iterator() { + return new ValueIterator(); + } + + /** + * Returns a cursor over the values of this deque (in tail to head order). The iterator is + * implemented as a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in + * the deque's buffer) use the cursor's public fields. An example is shown below. + * + *
+   * for (Iterator<IntCursor> i = intDeque.descendingIterator(); i.hasNext();) {
+   *   final IntCursor c = i.next();
+   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator descendingIterator() { + return new DescendingValueIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + forEach(procedure, head, tail); + return procedure; + } + + /** + * Applies procedure to a slice of the deque, fromIndex, inclusive, to + * toIndex, exclusive. + */ + private void forEach(CharProcedure procedure, int fromIndex, final int toIndex) { + final char[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + procedure.apply(buffer[i]); + } + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + int fromIndex = head; + int toIndex = tail; + + final char[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + if (!predicate.apply(buffer[i])) { + break; + } + } + + return predicate; + } + + /** Applies procedure to all elements of this deque, tail to head. */ + @Override + public T descendingForEach(T procedure) { + descendingForEach(procedure, head, tail); + return procedure; + } + + /** + * Applies procedure to a slice of the deque, toIndex, exclusive, down + * to fromIndex, inclusive. + */ + private void descendingForEach(CharProcedure procedure, int fromIndex, final int toIndex) { + if (fromIndex == toIndex) return; + + final char[] buffer = this.buffer; + int i = toIndex; + do { + i = oneLeft(i, buffer.length); + procedure.apply(buffer[i]); + } while (i != fromIndex); + } + + /** {@inheritDoc} */ + @Override + public T descendingForEach(T predicate) { + descendingForEach(predicate, head, tail); + return predicate; + } + + /** + * Applies predicate to a slice of the deque, toIndex, exclusive, down + * to fromIndex, inclusive or until the predicate returns false. + */ + private void descendingForEach(CharPredicate predicate, int fromIndex, final int toIndex) { + if (fromIndex == toIndex) return; + + final char[] buffer = this.buffer; + int i = toIndex; + do { + i = oneLeft(i, buffer.length); + if (!predicate.apply(buffer[i])) { + break; + } + } while (i != fromIndex); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharPredicate predicate) { + final char[] buffer = this.buffer; + final int last = tail; + final int bufLen = buffer.length; + int removed = 0; + int from, to; + from = to = head; + try { + for (from = to = head; from != last; from = oneRight(from, bufLen)) { + if (predicate.apply(buffer[from])) { + buffer[from] = ((char) 0); + removed++; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = ((char) 0); + } + + to = oneRight(to, bufLen); + } + } finally { + // Keep the deque in consistent state even if the predicate throws an exception. + for (; from != last; from = oneRight(from, bufLen)) { + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = ((char) 0); + } + + to = oneRight(to, bufLen); + } + tail = to; + } + + return removed; + } + + /** {@inheritDoc} */ + @Override + public boolean contains(char e) { + int fromIndex = head; + int toIndex = tail; + + final char[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + if (((e) == (buffer[i]))) { + return true; + } + } + + return false; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 1; + int fromIndex = head; + int toIndex = tail; + + final char[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + h = 31 * h + BitMixer.mix(this.buffer[i]); + } + return h; + } + + /** + * Returns true only if the other object is an instance of the same class and with + * the same elements. + */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Compare order-aligned elements against another {@link CharDeque}. */ + protected boolean equalElements(CharArrayDeque other) { + int max = size(); + if (other.size() != max) { + return false; + } + + Iterator i1 = this.iterator(); + Iterator i2 = other.iterator(); + + while (i1.hasNext() && i2.hasNext()) { + if (!((i1.next().value) == (i2.next().value))) { + return false; + } + } + + return !i1.hasNext() && !i2.hasNext(); + } + + /** Create a new deque by pushing a variable number of arguments to the end of it. */ + public static CharArrayDeque from(char... elements) { + final CharArrayDeque coll = new CharArrayDeque(elements.length); + coll.addLast(elements); + return coll; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/CharArrayList.java b/src/main/java/com/carrotsearch/hppc/CharArrayList.java new file mode 100755 index 00000000..90837d31 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharArrayList.java @@ -0,0 +1,579 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.CharPredicate; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** An array-backed list of chars. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java") +public class CharArrayList extends AbstractCharCollection + implements CharIndexedContainer, Preallocable, Cloneable, Accountable { + /** An immutable empty buffer (array). */ + public static final char[] EMPTY_ARRAY = new char[0]; + + ; + + /** Reuse the same strategy instance. */ + private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = + BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; + + /** + * Internal array for storing the list. The array may be larger than the current size ({@link + * #size()}). + */ + public char[] buffer = EMPTY_ARRAY; + + /** Current number of elements stored in {@link #buffer}. */ + public int elementsCount; + + /** Buffer resizing strategy. */ + protected final ArraySizingStrategy resizer; + + /** New instance with sane defaults. */ + public CharArrayList() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public CharArrayList(int expectedElements) { + this(expectedElements, DEFAULT_SIZING_STRATEGY); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public CharArrayList(int expectedElements, ArraySizingStrategy resizer) { + assert resizer != null; + this.resizer = resizer; + buffer = Arrays.copyOf(buffer, expectedElements); + } + + /** Creates a new list from the elements of another container in its iteration order. */ + public CharArrayList(CharContainer container) { + this(container.size()); + addAll(container); + } + + /** {@inheritDoc} */ + @Override + public void add(char e1) { + ensureBufferSpace(1); + buffer[elementsCount++] = e1; + } + + /** + * Appends two elements at the end of the list. To add more than two elements, use add + * (vararg-version) or access the buffer directly (tight loop). + */ + public void add(char e1, char e2) { + ensureBufferSpace(2); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + } + + /** Add all elements from a range of given array to the list. */ + public void add(char[] elements, int start, int length) { + assert length >= 0 : "Length must be >= 0"; + + ensureBufferSpace(length); + System.arraycopy(elements, start, buffer, elementsCount, length); + elementsCount += length; + } + + /** + * Vararg-signature method for adding elements at the end of the list. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + */ + public final void add(char... elements) { + add(elements, 0, elements.length); + } + + /** Adds all elements from another container. */ + public int addAll(CharContainer container) { + final int size = container.size(); + ensureBufferSpace(size); + + for (CharCursor cursor : container) { + add(cursor.value); + } + + return size; + } + + /** Adds all elements from another iterable. */ + public int addAll(Iterable iterable) { + int size = 0; + for (CharCursor cursor : iterable) { + add(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public void insert(int index, char e1) { + assert (index >= 0 && index <= size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + "]."; + + ensureBufferSpace(1); + System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index); + buffer[index] = e1; + elementsCount++; + } + + /** {@inheritDoc} */ + @Override + public char get(int index) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + return buffer[index]; + } + + /** {@inheritDoc} */ + @Override + public char set(int index, char e1) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + final char v = buffer[index]; + buffer[index] = e1; + return v; + } + + /** {@inheritDoc} */ + @Override + public char removeAt(int index) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + final char v = buffer[index]; + System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index); + + return v; + } + + /** {@inheritDoc} */ + @Override + public char removeLast() { + assert elementsCount > 0; + + final char v = buffer[--elementsCount]; + + return v; + } + + /** {@inheritDoc} */ + @Override + public void removeRange(int fromIndex, int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex); + final int count = toIndex - fromIndex; + elementsCount -= count; + } + + /** {@inheritDoc} */ + @Override + public boolean removeElement(char e1) { + return removeFirst(e1) != -1; + } + + /** {@inheritDoc} */ + @Override + public int removeFirst(char e1) { + final int index = indexOf(e1); + if (index >= 0) removeAt(index); + return index; + } + + /** {@inheritDoc} */ + @Override + public int removeLast(char e1) { + final int index = lastIndexOf(e1); + if (index >= 0) removeAt(index); + return index; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(char e1) { + int to = 0; + for (int from = 0; from < elementsCount; from++) { + if (((e1) == (buffer[from]))) { + continue; + } + if (to != from) { + buffer[to] = buffer[from]; + } + to++; + } + final int deleted = elementsCount - to; + this.elementsCount = to; + + return deleted; + } + + /** {@inheritDoc} */ + @Override + public boolean contains(char e1) { + return indexOf(e1) >= 0; + } + + /** {@inheritDoc} */ + @Override + public int indexOf(char e1) { + for (int i = 0; i < elementsCount; i++) { + if (((e1) == (buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int lastIndexOf(char e1) { + for (int i = elementsCount - 1; i >= 0; i--) { + if (((e1) == (buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return elementsCount == 0; + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + final int bufferLen = (buffer == null ? 0 : buffer.length); + if (expectedElements > bufferLen) { + ensureBufferSpace(expectedElements - size()); + } + } + + /** + * Ensures the internal buffer has enough free slots to store expectedAdditions. + * Increases internal buffer size if needed. + */ + protected void ensureBufferSpace(int expectedAdditions) { + final int bufferLen = (buffer == null ? 0 : buffer.length); + if (elementsCount + expectedAdditions > bufferLen) { + final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions); + assert newSize >= elementsCount + expectedAdditions + : "Resizer failed to" + + " return sensible new size: " + + newSize + + " <= " + + (elementsCount + expectedAdditions); + + this.buffer = Arrays.copyOf(buffer, newSize); + } + } + + /** + * Truncate or expand the list to the new size. If the list is truncated, the buffer will not be + * reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated + * values will be reset to the default value (zero). If the list is expanded, the elements beyond + * the current size are initialized with JVM-defaults (zero or null values). + */ + public void resize(int newSize) { + if (newSize <= buffer.length) { + if (newSize < elementsCount) { + Arrays.fill(buffer, newSize, elementsCount, ((char) 0)); + } else { + Arrays.fill(buffer, elementsCount, newSize, ((char) 0)); + } + } else { + ensureCapacity(newSize); + } + this.elementsCount = newSize; + } + + /** {@inheritDoc} */ + @Override + public int size() { + return elementsCount; + } + + /** Trim the internal buffer to the current size. */ + public void trimToSize() { + if (size() != this.buffer.length) { + this.buffer = toArray(); + } + } + + /** + * Sets the number of stored elements to zero. Releases and initializes the internal storage array + * to default values. To clear the list without cleaning the buffer, simply set the {@link + * #elementsCount} field to zero. + */ + @Override + public void clear() { + Arrays.fill(buffer, 0, elementsCount, ((char) 0)); + this.elementsCount = 0; + } + + /** Sets the number of stored elements to zero and releases the internal storage array. */ + @Override + public void release() { + this.buffer = EMPTY_ARRAY; + this.elementsCount = 0; + } + + /** + * {@inheritDoc} + * + *

The returned array is sized to match exactly the number of elements of the stack. + */ + @Override + public char[] toArray() { + + return Arrays.copyOf(buffer, elementsCount); + } + + /** {@inheritDoc} */ + @Override + public CharIndexedContainer sort() { + Arrays.sort(buffer, 0, elementsCount); + return this; + } + + /** {@inheritDoc} */ + @Override + public CharIndexedContainer reverse() { + for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) { + char tmp = buffer[i]; + buffer[i] = buffer[j]; + buffer[j] = tmp; + } + return this; + } + + /** + * Clone this object. The returned clone will reuse the same hash function and array resizing + * strategy. + */ + @Override + public CharArrayList clone() { + try { + + final CharArrayList cloned = (CharArrayList) super.clone(); + cloned.buffer = buffer.clone(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 1, max = elementsCount; + for (int i = 0; i < max; i++) { + h = 31 * h + BitMixer.mix(this.buffer[i]); + } + return h; + } + + /** + * Returns true only if the other object is an instance of the same class and with + * the same elements. + */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Compare index-aligned elements against another {@link CharIndexedContainer}. */ + protected boolean equalElements(CharArrayList other) { + int max = size(); + if (other.size() != max) { + return false; + } + + for (int i = 0; i < max; i++) { + if (!((get(i)) == (other.get(i)))) { + return false; + } + } + + return true; + } + + @Override + public long ramBytesAllocated() { + // int: elementsCount + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES + + resizer.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(buffer); + } + + @Override + public long ramBytesUsed() { + // int: elementsCount + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES + + resizer.ramBytesUsed() + + RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount); + } + + /** An iterator implementation for {@link CharArrayList#iterator}. */ + static final class ValueIterator extends AbstractIterator { + private final CharCursor cursor; + + private final char[] buffer; + private final int size; + + public ValueIterator(char[] buffer, int size) { + this.cursor = new CharCursor(); + this.cursor.index = -1; + this.size = size; + this.buffer = buffer; + } + + @Override + protected CharCursor fetch() { + if (cursor.index + 1 == size) return done(); + + cursor.value = buffer[++cursor.index]; + return cursor; + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new ValueIterator(buffer, size()); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + return forEach(procedure, 0, size()); + } + + /** + * Applies procedure to a slice of the list, fromIndex, inclusive, to + * toIndex, exclusive. + */ + public T forEach(T procedure, int fromIndex, final int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + final char[] buffer = this.buffer; + for (int i = fromIndex; i < toIndex; i++) { + procedure.apply(buffer[i]); + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharPredicate predicate) { + final char[] buffer = this.buffer; + final int elementsCount = this.elementsCount; + int to = 0; + int from = 0; + try { + for (; from < elementsCount; from++) { + if (predicate.apply(buffer[from])) { + buffer[from] = ((char) 0); + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = ((char) 0); + } + to++; + } + } finally { + // Keep the list in a consistent state, even if the predicate throws an exception. + for (; from < elementsCount; from++) { + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = ((char) 0); + } + to++; + } + + this.elementsCount = to; + } + + return elementsCount - to; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + return forEach(predicate, 0, size()); + } + + /** + * Applies predicate to a slice of the list, fromIndex, inclusive, to + * toIndex, exclusive, or until predicate returns false. + */ + public T forEach(T predicate, int fromIndex, final int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + final char[] buffer = this.buffer; + for (int i = fromIndex; i < toIndex; i++) { + if (!predicate.apply(buffer[i])) break; + } + + return predicate; + } + + /** + * Create a list from a variable number of arguments or an array of char. The + * elements are copied from the argument to the internal buffer. + */ + public static CharArrayList from(char... elements) { + final CharArrayList list = new CharArrayList(elements.length); + list.add(elements); + return list; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/CharBufferVisualizer.java b/src/main/java/com/carrotsearch/hppc/CharBufferVisualizer.java new file mode 100755 index 00000000..7bd17436 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharBufferVisualizer.java @@ -0,0 +1,33 @@ +package com.carrotsearch.hppc; + +/** + * Reused buffer visualization routines. + * + * @see CharSet#visualizeKeyDistribution(int) + * @see CharVTypeMap#visualizeKeyDistribution(int) + */ +class CharBufferVisualizer { + static String visualizeKeyDistribution(char[] buffer, int max, int characters) { + final StringBuilder b = new StringBuilder(); + final char[] chars = ".123456789X".toCharArray(); + for (int i = 1, start = -1; i <= characters; i++) { + int end = (int) ((long) i * max / characters); + + if (start + 1 <= end) { + int taken = 0; + int slots = 0; + for (int slot = start + 1; slot <= end; slot++, slots++) { + if (!((buffer[slot]) == 0)) { + taken++; + } + } + b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]); + start = end; + } + } + while (b.length() < characters) { + b.append(' '); + } + return b.toString(); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/CharByteAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/CharByteAssociativeContainer.java new file mode 100755 index 00000000..a69b4beb --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharByteAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see CharContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface CharByteAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(char key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharBytePredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link CharByteProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link CharBytePredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(char key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(char[] fromKeys, byte[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final char[] keys = this.keys; + final byte[] values = this.values; + final int mask = this.mask; + char existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + char[] prevKeys = this.keys; + byte[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new char[arraySize + emptyElementSlot]); + this.values = (new byte[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, char pendingKey, byte pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final char[] prevKeys = this.keys; + final byte[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final char[] keys = this.keys; + final byte[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final char existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = ((char) 0); + values[gapSlot] = ((byte) 0); + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/CharByteMap.java b/src/main/java/com/carrotsearch/hppc/CharByteMap.java new file mode 100755 index 00000000..dcb4ef54 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharByteMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.CharByteCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface CharByteMap extends CharByteAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public byte get(char key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public byte getOrDefault(char key, byte defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public byte put(char key, byte value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(char key, byte value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(CharByteAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public byte putOrAdd(char key, byte putValue, byte incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public byte addTo(char key, byte additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public byte remove(char key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link CharByteMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(char key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public byte indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public byte indexReplace(int index, byte newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, char key, byte value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public byte indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharCharAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/CharCharAssociativeContainer.java new file mode 100755 index 00000000..b7334bbc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharCharAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see CharContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface CharCharAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(char key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharCharPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link CharCharProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link CharCharPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public CharCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public CharContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharCharHashMap.java b/src/main/java/com/carrotsearch/hppc/CharCharHashMap.java new file mode 100755 index 00000000..509c1a2c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharCharHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of char to char, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class CharCharHashMap implements CharCharMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public char[] keys; + + /** The array holding values. */ + public char[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public CharCharHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public CharCharHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public CharCharHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public CharCharHashMap(CharCharAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public char put(char key, char value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + char previousValue = hasEmptyKey ? values[mask + 1] : ((char) 0); + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final char previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return ((char) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(CharCharAssociativeContainer container) { + final int count = size(); + for (CharCharCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (CharCharCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public char putOrAdd(char key, char putValue, char incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((char) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public char addTo(char key, char incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public char remove(char key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return ((char) 0); + } + hasEmptyKey = false; + char previousValue = values[mask + 1]; + values[mask + 1] = ((char) 0); + return previousValue; + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final char previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return ((char) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof CharLookupContainer) { + if (hasEmptyKey && other.contains(((char) 0))) { + hasEmptyKey = false; + values[mask + 1] = ((char) 0); + } + + final char[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + char existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (CharCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharCharPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(((char) 0), values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = ((char) 0); + } + } + + final char[] keys = this.keys; + final char[] values = this.values; + for (int slot = 0; slot <= mask; ) { + char existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(((char) 0))) { + hasEmptyKey = false; + values[mask + 1] = ((char) 0); + } + } + + final char[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + char existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public char get(char key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : ((char) 0); + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return ((char) 0); + } + } + + /** {@inheritDoc} */ + @Override + public char getOrDefault(char key, char defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(char key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(char key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public char indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public char indexReplace(int index, char newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + char previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, char key, char value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public char indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + char previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = ((char) 0); + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, ((char) 0)); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (CharCharCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(CharCharHashMap other) { + if (other.size() != size()) { + return false; + } + + for (CharCharCursor c : other) { + char key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final char[] prevKeys = this.keys; + final char[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final CharCharCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new CharCharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharCharCursor fetch() { + final int mask = CharCharHashMap.this.mask; + while (index <= mask) { + char existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = ((char) 0); + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final char[] keys = this.keys; + final char[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(((char) 0), values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final char[] keys = this.keys; + final char[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(((char) 0), values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { + private final CharCharHashMap owner = CharCharHashMap.this; + + @Override + public boolean contains(char e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((CharCharProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((CharCharPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(CharPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final char e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final CharCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new CharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharCursor fetch() { + final int mask = CharCharHashMap.this.mask; + while (index <= mask) { + char existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = ((char) 0); + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public CharCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractCharCollection { + private final CharCharHashMap owner = CharCharHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(char value) { + for (CharCharCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (CharCharCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (CharCharCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final char e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final CharPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final CharCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new CharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharCursor fetch() { + final int mask = CharCharHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public CharCharHashMap clone() { + try { + + CharCharHashMap cloned = (CharCharHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (CharCharCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static CharCharHashMap from(char[] keys, char[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + CharCharHashMap map = new CharCharHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(char key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(char[] fromKeys, char[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final char[] keys = this.keys; + final char[] values = this.values; + final int mask = this.mask; + char existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + char[] prevKeys = this.keys; + char[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new char[arraySize + emptyElementSlot]); + this.values = (new char[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, char pendingKey, char pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final char[] prevKeys = this.keys; + final char[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final char[] keys = this.keys; + final char[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final char existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = ((char) 0); + values[gapSlot] = ((char) 0); + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/CharCharMap.java b/src/main/java/com/carrotsearch/hppc/CharCharMap.java new file mode 100755 index 00000000..c3690bba --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharCharMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.CharCharCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface CharCharMap extends CharCharAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public char get(char key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public char getOrDefault(char key, char defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public char put(char key, char value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(char key, char value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(CharCharAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public char putOrAdd(char key, char putValue, char incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public char addTo(char key, char additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public char remove(char key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link CharCharMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(char key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public char indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public char indexReplace(int index, char newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, char key, char value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public char indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharCollection.java b/src/main/java/com/carrotsearch/hppc/CharCollection.java new file mode 100755 index 00000000..4cc8517b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharCollection.java @@ -0,0 +1,64 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.predicates.CharPredicate; + +/** + * A collection allows basic, efficient operations on sets of elements (difference and + * intersection). + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java") +public interface CharCollection extends CharContainer { + /** + * Removes all occurrences of e from this collection. + * + * @param e Element to be removed from this collection, if present. + * @return The number of removed elements as a result of this call. + */ + public int removeAll(char e); + + /** + * Removes all elements in this collection that are present in c. + * + * @return Returns the number of removed elements. + */ + public int removeAll(CharLookupContainer c); + + /** + * Removes all elements in this collection for which the given predicate returns true + * . + * + * @return Returns the number of removed elements. + */ + public int removeAll(CharPredicate predicate); + + /** + * Keeps all elements in this collection that are present in c. Runs in time + * proportional to the number of elements in this collection. Equivalent of sets intersection. + * + * @return Returns the number of removed elements. + */ + public int retainAll(CharLookupContainer c); + + /** + * Keeps all elements in this collection for which the given predicate returns true. + * + * @return Returns the number of removed elements. + */ + public int retainAll(CharPredicate predicate); + + /** + * Removes all elements from this collection. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharContainer.java b/src/main/java/com/carrotsearch/hppc/CharContainer.java new file mode 100755 index 00000000..5977583b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharContainer.java @@ -0,0 +1,76 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.CharCursor; +import com.carrotsearch.hppc.predicates.CharPredicate; +import com.carrotsearch.hppc.procedures.CharProcedure; +import java.util.Iterator; + +/** A generic container holding chars. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java") +public interface CharContainer extends Iterable { + /** + * Returns an iterator to a cursor traversing the collection. The order of traversal is not + * defined. More than one cursor may be active at a time. The behavior of iterators is undefined + * if structural changes are made to the underlying collection. + * + *

The iterator is implemented as a cursor and it returns the same cursor instance on + * every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current + * list's value (or index in the list) use the cursor's public fields. An example is shown below. + * + *

+   * for (CharCursor<char> c : container) {
+   *   System.out.println("index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator iterator(); + + /** + * Lookup a given element in the container. This operation has no speed guarantees (may be linear + * with respect to the size of this container). + * + * @return Returns true if this container has an element equal to e. + */ + public boolean contains(char e); + + /** + * Return the current number of elements in this container. The time for calculating the + * container's size may take O(n) time, although implementing classes should try to + * maintain the current size and return in constant time. + */ + public int size(); + + /** Shortcut for size() == 0. */ + public boolean isEmpty(); + + /** + * Copies all elements of this container to an array. + * + *

The returned array is always a copy, regardless of the storage used by the container. + */ + public char[] toArray(); + + /** + * Applies a procedure to all container elements. Returns the argument (any subclass + * of {@link CharProcedure}. This lets the caller to call methods of the argument by chaining the + * call (even if the argument is an anonymous type) to retrieve computed values, for example + * (IntContainer): + * + *

+   * int count = container.forEach(new IntProcedure() {
+   *   int count; // this is a field declaration in an anonymous class.
+   *
+   *   public void apply(int value) {
+   *     count++;
+   *   }
+   * }).count;
+   * 
+ */ + public T forEach(T procedure); + + /** + * Applies a predicate to container elements as long, as the predicate returns + * true. The iteration is interrupted otherwise. + */ + public T forEach(T predicate); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharDeque.java b/src/main/java/com/carrotsearch/hppc/CharDeque.java new file mode 100755 index 00000000..34ff5c92 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharDeque.java @@ -0,0 +1,77 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.CharCursor; +import com.carrotsearch.hppc.predicates.CharPredicate; +import com.carrotsearch.hppc.procedures.CharProcedure; +import java.util.Deque; +import java.util.Iterator; + +/** + * A linear collection that supports element insertion and removal at both ends. + * + * @see Deque + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java") +public interface CharDeque extends CharCollection { + /** + * Removes the first element that equals e. + * + * @return The deleted element's index or -1 if the element was not found. + */ + public int removeFirst(char e); + + /** + * Removes the last element that equals e. + * + * @return The deleted element's index or -1 if the element was not found. + */ + public int removeLast(char e); + + /** Inserts the specified element at the front of this deque. */ + public void addFirst(char e); + + /** Inserts the specified element at the end of this deque. */ + public void addLast(char e); + + /** + * Retrieves and removes the first element of this deque. + * + * @return the head (first) element of this deque. + */ + public char removeFirst(); + + /** + * Retrieves and removes the last element of this deque. + * + * @return the tail of this deque. + */ + public char removeLast(); + + /** + * Retrieves the first element of this deque but does not remove it. + * + * @return the head of this deque. + */ + public char getFirst(); + + /** + * Retrieves the last element of this deque but does not remove it. + * + * @return the head of this deque. + */ + public char getLast(); + + /** + * @return An iterator over elements in this deque in tail-to-head order. + */ + public Iterator descendingIterator(); + + /** Applies a procedure to all elements in tail-to-head order. */ + public T descendingForEach(T procedure); + + /** + * Applies a predicate to container elements as long, as the predicate returns + * true. The iteration is interrupted otherwise. + */ + public T descendingForEach(T predicate); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharDoubleAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/CharDoubleAssociativeContainer.java new file mode 100755 index 00000000..2d898f2c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharDoubleAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see CharContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface CharDoubleAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *
+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(char key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharDoublePredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link CharDoubleProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link CharDoublePredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public CharCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public DoubleContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/CharDoubleHashMap.java new file mode 100755 index 00000000..0a68bfaf --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharDoubleHashMap.java @@ -0,0 +1,1082 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of char to double, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class CharDoubleHashMap implements CharDoubleMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public char[] keys; + + /** The array holding values. */ + public double[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public CharDoubleHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public CharDoubleHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public CharDoubleHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public CharDoubleHashMap(CharDoubleAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public double put(char key, double value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + double previousValue = hasEmptyKey ? values[mask + 1] : 0d; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final double previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0d; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(CharDoubleAssociativeContainer container) { + final int count = size(); + for (CharDoubleCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (CharDoubleCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public double putOrAdd(char key, double putValue, double incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((double) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public double addTo(char key, double incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public double remove(char key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return 0d; + } + hasEmptyKey = false; + double previousValue = values[mask + 1]; + values[mask + 1] = 0d; + return previousValue; + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final double previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0d; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof CharLookupContainer) { + if (hasEmptyKey && other.contains(((char) 0))) { + hasEmptyKey = false; + values[mask + 1] = 0d; + } + + final char[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + char existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (CharCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharDoublePredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(((char) 0), values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0d; + } + } + + final char[] keys = this.keys; + final double[] values = this.values; + for (int slot = 0; slot <= mask; ) { + char existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(((char) 0))) { + hasEmptyKey = false; + values[mask + 1] = 0d; + } + } + + final char[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + char existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public double get(char key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : 0d; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0d; + } + } + + /** {@inheritDoc} */ + @Override + public double getOrDefault(char key, double defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(char key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(char key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public double indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public double indexReplace(int index, double newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + double previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, char key, double value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public double indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + double previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0d; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, ((char) 0)); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (CharDoubleCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(CharDoubleHashMap other) { + if (other.size() != size()) { + return false; + } + + for (CharDoubleCursor c : other) { + char key = c.key; + if (!containsKey(key) + || !(Double.doubleToLongBits(c.value) == Double.doubleToLongBits(get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final char[] prevKeys = this.keys; + final double[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final CharDoubleCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new CharDoubleCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharDoubleCursor fetch() { + final int mask = CharDoubleHashMap.this.mask; + while (index <= mask) { + char existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = ((char) 0); + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final char[] keys = this.keys; + final double[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(((char) 0), values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final char[] keys = this.keys; + final double[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(((char) 0), values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { + private final CharDoubleHashMap owner = CharDoubleHashMap.this; + + @Override + public boolean contains(char e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((CharDoubleProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((CharDoublePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(CharPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final char e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final CharCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new CharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharCursor fetch() { + final int mask = CharDoubleHashMap.this.mask; + while (index <= mask) { + char existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = ((char) 0); + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public DoubleCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractDoubleCollection { + private final CharDoubleHashMap owner = CharDoubleHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(double value) { + for (CharDoubleCursor c : owner) { + if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (CharDoubleCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (CharDoubleCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final double e) { + return owner.removeAll( + (key, value) -> (Double.doubleToLongBits(e) == Double.doubleToLongBits(value))); + } + + @Override + public int removeAll(final DoublePredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final DoubleCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new DoubleCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected DoubleCursor fetch() { + final int mask = CharDoubleHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public CharDoubleHashMap clone() { + try { + + CharDoubleHashMap cloned = (CharDoubleHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (CharDoubleCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static CharDoubleHashMap from(char[] keys, double[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + CharDoubleHashMap map = new CharDoubleHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(char key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(char[] fromKeys, double[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final char[] keys = this.keys; + final double[] values = this.values; + final int mask = this.mask; + char existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + char[] prevKeys = this.keys; + double[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new char[arraySize + emptyElementSlot]); + this.values = (new double[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, char pendingKey, double pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final char[] prevKeys = this.keys; + final double[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final char[] keys = this.keys; + final double[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final char existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = ((char) 0); + values[gapSlot] = 0d; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/CharDoubleMap.java b/src/main/java/com/carrotsearch/hppc/CharDoubleMap.java new file mode 100755 index 00000000..2ba6e41b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharDoubleMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.CharDoubleCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface CharDoubleMap extends CharDoubleAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public double get(char key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public double getOrDefault(char key, double defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public double put(char key, double value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(char key, double value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(CharDoubleAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public double putOrAdd(char key, double putValue, double incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public double addTo(char key, double additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public double remove(char key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link CharDoubleMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(char key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public double indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public double indexReplace(int index, double newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, char key, double value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public double indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharFloatAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/CharFloatAssociativeContainer.java new file mode 100755 index 00000000..10069a39 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharFloatAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see CharContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface CharFloatAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(char key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharFloatPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link CharFloatProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link CharFloatPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public CharCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public FloatContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/CharFloatHashMap.java new file mode 100755 index 00000000..0f4d6d8f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharFloatHashMap.java @@ -0,0 +1,1081 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of char to float, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class CharFloatHashMap implements CharFloatMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public char[] keys; + + /** The array holding values. */ + public float[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public CharFloatHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public CharFloatHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public CharFloatHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public CharFloatHashMap(CharFloatAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public float put(char key, float value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + float previousValue = hasEmptyKey ? values[mask + 1] : 0f; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final float previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0f; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(CharFloatAssociativeContainer container) { + final int count = size(); + for (CharFloatCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (CharFloatCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public float putOrAdd(char key, float putValue, float incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((float) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public float addTo(char key, float incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public float remove(char key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return 0f; + } + hasEmptyKey = false; + float previousValue = values[mask + 1]; + values[mask + 1] = 0f; + return previousValue; + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final float previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0f; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof CharLookupContainer) { + if (hasEmptyKey && other.contains(((char) 0))) { + hasEmptyKey = false; + values[mask + 1] = 0f; + } + + final char[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + char existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (CharCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharFloatPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(((char) 0), values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0f; + } + } + + final char[] keys = this.keys; + final float[] values = this.values; + for (int slot = 0; slot <= mask; ) { + char existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(((char) 0))) { + hasEmptyKey = false; + values[mask + 1] = 0f; + } + } + + final char[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + char existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public float get(char key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : 0f; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0f; + } + } + + /** {@inheritDoc} */ + @Override + public float getOrDefault(char key, float defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(char key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(char key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public float indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public float indexReplace(int index, float newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + float previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, char key, float value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public float indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + float previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0f; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, ((char) 0)); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (CharFloatCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(CharFloatHashMap other) { + if (other.size() != size()) { + return false; + } + + for (CharFloatCursor c : other) { + char key = c.key; + if (!containsKey(key) || !(Float.floatToIntBits(c.value) == Float.floatToIntBits(get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final char[] prevKeys = this.keys; + final float[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final CharFloatCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new CharFloatCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharFloatCursor fetch() { + final int mask = CharFloatHashMap.this.mask; + while (index <= mask) { + char existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = ((char) 0); + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final char[] keys = this.keys; + final float[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(((char) 0), values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final char[] keys = this.keys; + final float[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(((char) 0), values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { + private final CharFloatHashMap owner = CharFloatHashMap.this; + + @Override + public boolean contains(char e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((CharFloatProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((CharFloatPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(CharPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final char e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final CharCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new CharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharCursor fetch() { + final int mask = CharFloatHashMap.this.mask; + while (index <= mask) { + char existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = ((char) 0); + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public FloatCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractFloatCollection { + private final CharFloatHashMap owner = CharFloatHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(float value) { + for (CharFloatCursor c : owner) { + if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (CharFloatCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (CharFloatCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final float e) { + return owner.removeAll( + (key, value) -> (Float.floatToIntBits(e) == Float.floatToIntBits(value))); + } + + @Override + public int removeAll(final FloatPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final FloatCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new FloatCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected FloatCursor fetch() { + final int mask = CharFloatHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public CharFloatHashMap clone() { + try { + + CharFloatHashMap cloned = (CharFloatHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (CharFloatCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static CharFloatHashMap from(char[] keys, float[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + CharFloatHashMap map = new CharFloatHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(char key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(char[] fromKeys, float[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final char[] keys = this.keys; + final float[] values = this.values; + final int mask = this.mask; + char existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + char[] prevKeys = this.keys; + float[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new char[arraySize + emptyElementSlot]); + this.values = (new float[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, char pendingKey, float pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final char[] prevKeys = this.keys; + final float[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final char[] keys = this.keys; + final float[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final char existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = ((char) 0); + values[gapSlot] = 0f; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/CharFloatMap.java b/src/main/java/com/carrotsearch/hppc/CharFloatMap.java new file mode 100755 index 00000000..4bf7569f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharFloatMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.CharFloatCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface CharFloatMap extends CharFloatAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public float get(char key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public float getOrDefault(char key, float defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public float put(char key, float value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(char key, float value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(CharFloatAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public float putOrAdd(char key, float putValue, float incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public float addTo(char key, float additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public float remove(char key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link CharFloatMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(char key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public float indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public float indexReplace(int index, float newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, char key, float value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public float indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharHashSet.java b/src/main/java/com/carrotsearch/hppc/CharHashSet.java new file mode 100755 index 00000000..58ad8f26 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharHashSet.java @@ -0,0 +1,787 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash set of chars, implemented using open addressing with linear probing for + * collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeHashSet.java") +public class CharHashSet extends AbstractCharCollection + implements CharLookupContainer, CharSet, Preallocable, Cloneable, Accountable { + /** The hash array holding keys. */ + public char[] keys; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any. + * + * @see #size() + * @see #hasEmptyKey + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** + * New instance with sane defaults. + * + * @see #CharHashSet(int, double) + */ + public CharHashSet() { + this(DEFAULT_EXPECTED_ELEMENTS, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with sane defaults. + * + * @see #CharHashSet(int, double) + */ + public CharHashSet(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public CharHashSet(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** New instance copying elements from another {@link CharContainer}. */ + public CharHashSet(CharContainer container) { + this(container.size()); + addAll(container); + } + + /** {@inheritDoc} */ + @Override + public boolean add(char key) { + if (((key) == 0)) { + assert ((keys[mask + 1]) == 0); + boolean added = !hasEmptyKey; + hasEmptyKey = true; + return added; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return false; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key); + } else { + keys[slot] = key; + } + + assigned++; + return true; + } + } + + /** + * Adds all elements from the given list (vararg) to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + */ + public final int addAll(char... elements) { + ensureCapacity(elements.length); + int count = 0; + for (char e : elements) { + if (add(e)) { + count++; + } + } + return count; + } + + /** + * Adds all elements from the given {@link CharContainer} to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + */ + public int addAll(CharContainer container) { + ensureCapacity(container.size()); + return addAll((Iterable) container); + } + + /** + * Adds all elements from the given iterable to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + */ + public int addAll(Iterable iterable) { + int count = 0; + for (CharCursor cursor : iterable) { + if (add(cursor.value)) { + count++; + } + } + return count; + } + + /** {@inheritDoc} */ + @Override + public char[] toArray() { + + final char[] cloned = (new char[size()]); + int j = 0; + if (hasEmptyKey) { + cloned[j++] = ((char) 0); + } + + final char[] keys = this.keys; + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + char existing; + if (!((existing = keys[slot]) == 0)) { + cloned[j++] = existing; + } + } + + return cloned; + } + + /** An alias for the (preferred) {@link #removeAll}. */ + public boolean remove(char key) { + if (((key) == 0)) { + boolean hadEmptyKey = hasEmptyKey; + hasEmptyKey = false; + return hadEmptyKey; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + shiftConflictingKeys(slot); + return true; + } + slot = (slot + 1) & mask; + } + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(char key) { + return remove(key) ? 1 : 0; + } + + /** + * Removes all keys present in a given container. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharContainer other) { + final int before = size(); + + // Try to iterate over the smaller set or over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof CharLookupContainer) { + if (hasEmptyKey && other.contains(((char) 0))) { + hasEmptyKey = false; + } + + final char[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + char existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (CharCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharPredicate predicate) { + int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(((char) 0))) { + hasEmptyKey = false; + } + } + + final char[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + char existing; + if (!((existing = keys[slot]) == 0)) { + if (predicate.apply(existing)) { + shiftConflictingKeys(slot); + continue; // Repeat the check for the same slot i (shifted). + } + } + slot++; + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public boolean contains(char key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + return false; + } + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + Arrays.fill(keys, ((char) 0)); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + keys = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return size() == 0; + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final char[] prevKeys = this.keys; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys); + } + } + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + final char[] keys = this.keys; + for (int slot = mask; slot >= 0; slot--) { + char existing; + if (!((existing = keys[slot]) == 0)) { + h += BitMixer.mix(existing); + } + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && sameKeys(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + private boolean sameKeys(CharSet other) { + if (other.size() != size()) { + return false; + } + + for (CharCursor c : other) { + if (!contains(c.value)) { + return false; + } + } + + return true; + } + + /** {@inheritDoc} */ + @Override + public CharHashSet clone() { + try { + + CharHashSet cloned = (CharHashSet) super.clone(); + cloned.keys = keys.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + @Override + public long ramBytesAllocated() { + // int: assigned, mask, keyMixer, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys); + } + + @Override + public long ramBytesUsed() { + // int: assigned, mask, keyMixer, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + protected final class EntryIterator extends AbstractIterator { + private final CharCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new CharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharCursor fetch() { + final int mask = CharHashSet.this.mask; + while (index <= mask) { + char existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = ((char) 0); + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + if (hasEmptyKey) { + procedure.apply(((char) 0)); + } + + final char[] keys = this.keys; + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + char existing; + if (!((existing = keys[slot]) == 0)) { + procedure.apply(existing); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + if (hasEmptyKey) { + if (!predicate.apply(((char) 0))) { + return predicate; + } + } + + final char[] keys = this.keys; + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + char existing; + if (!((existing = keys[slot]) == 0)) { + if (!predicate.apply(existing)) { + break; + } + } + } + + return predicate; + } + + /** + * Create a set from a variable number of arguments or an array of char. The elements + * are copied from the argument to the internal buffer. + */ + public static CharHashSet from(char... elements) { + final CharHashSet set = new CharHashSet(elements.length); + set.addAll(elements); + return set; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(char key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up logic in + * certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between modifications (it will not be affected by read-only + * operations). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the set. + * @return A non-negative value of the logical "index" of the key in the set or a negative value + * if the key did not exist. + */ + public int indexOf(char key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index) { + assert index < 0 || index <= mask || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** + * Returns the exact value of the existing key. This method makes sense for sets of objects which + * define custom key-equality relationship. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the equivalent key currently stored in the set. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public char indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return keys[index]; + } + + /** + * Replaces the existing equivalent key with the given one and returns any previous value stored + * for that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @param equivalentKey The key to put in the set as a replacement. Must be equivalent to the key + * currently stored at the provided index. + * @return Returns the previous key stored in the set. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public char indexReplace(int index, char equivalentKey) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + assert ((keys[index]) == (equivalentKey)); + + char previousValue = keys[index]; + keys[index] = equivalentKey; + return previousValue; + } + + /** + * Inserts a key for an index that is not present in the set. This method may help in avoiding + * double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public void indexInsert(int index, char key) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + assert ((keys[index]) == 0); + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key); + } else { + keys[index] = key; + } + + assigned++; + } + } + + /** + * Removes a key at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public void indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + if (index > mask) { + hasEmptyKey = false; + } else { + shiftConflictingKeys(index); + } + } + + @Override + public String visualizeKeyDistribution(int characters) { + return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(char[] fromKeys) { + assert HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored keys into the new buffers. + final char[] keys = this.keys; + final int mask = this.mask; + char existing; + for (int i = fromKeys.length - 1; --i >= 0; ) { + if (!((existing = fromKeys[i]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + char[] prevKeys = this.keys; + try { + int emptyElementSlot = 1; + this.keys = (new char[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.keys == null ? 0 : size(), arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key to be inserted into the buffer but there is not + * enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, char pendingKey) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final char[] prevKeys = this.keys; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + + // Rehash old keys, including the pending key. + rehash(prevKeys); + } + + /** Shift all the slot-conflicting keys allocated to (and including) slot. */ + protected void shiftConflictingKeys(int gapSlot) { + final char[] keys = this.keys; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final char existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = ((char) 0); + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/CharIndexedContainer.java b/src/main/java/com/carrotsearch/hppc/CharIndexedContainer.java new file mode 100755 index 00000000..96824521 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharIndexedContainer.java @@ -0,0 +1,91 @@ +package com.carrotsearch.hppc; + +import java.util.RandomAccess; + +/** + * An indexed container provides random access to elements based on an index. Indexes + * are zero-based. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeIndexedContainer.java") +public interface CharIndexedContainer extends CharCollection, RandomAccess { + /** + * Removes the first element that equals e1, returning whether an element has been + * removed. + */ + public boolean removeElement(char e1); + + /** + * Removes the first element that equals e1, returning its deleted position or + * -1 if the element was not found. + */ + public int removeFirst(char e1); + + /** + * Removes the last element that equals e1, returning its deleted position or + * -1 if the element was not found. + */ + public int removeLast(char e1); + + /** + * Returns the index of the first occurrence of the specified element in this list, or -1 if this + * list does not contain the element. + */ + public int indexOf(char e1); + + /** + * Returns the index of the last occurrence of the specified element in this list, or -1 if this + * list does not contain the element. + */ + public int lastIndexOf(char e1); + + /** Adds an element to the end of this container (the last index is incremented by one). */ + public void add(char e1); + + /** + * Inserts the specified element at the specified position in this list. + * + * @param index The index at which the element should be inserted, shifting any existing and + * subsequent elements to the right. + */ + public void insert(int index, char e1); + + /** + * Replaces the element at the specified position in this list with the specified element. + * + * @return Returns the previous value in the list. + */ + public char set(int index, char e1); + + /** + * @return Returns the element at index index from the list. + */ + public char get(int index); + + /** + * Removes the element at the specified position in this container and returns it. + * + * @see #removeFirst + * @see #removeLast + * @see #removeAll + */ + public char removeAt(int index); + + /** Removes and returns the last element of this container. This container must not be empty. */ + public char removeLast(); + + /** + * Removes from this container all of the elements with indexes between fromIndex, + * inclusive, and toIndex, exclusive. + */ + public void removeRange(int fromIndex, int toIndex); + + /** Returns this container elements as a stream. */ + + /** Sorts the elements in this container and returns this container. */ + public CharIndexedContainer sort(); + + /** Reverses the elements in this container and returns this container. */ + public CharIndexedContainer reverse(); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharIntAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/CharIntAssociativeContainer.java new file mode 100755 index 00000000..08c5d64a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharIntAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see CharContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface CharIntAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(char key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharIntPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link CharIntProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link CharIntPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public CharCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public IntContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharIntHashMap.java b/src/main/java/com/carrotsearch/hppc/CharIntHashMap.java new file mode 100755 index 00000000..aff7e50d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharIntHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of char to int, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class CharIntHashMap implements CharIntMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public char[] keys; + + /** The array holding values. */ + public int[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public CharIntHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public CharIntHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public CharIntHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public CharIntHashMap(CharIntAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public int put(char key, int value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + int previousValue = hasEmptyKey ? values[mask + 1] : 0; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final int previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(CharIntAssociativeContainer container) { + final int count = size(); + for (CharIntCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (CharIntCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public int putOrAdd(char key, int putValue, int incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((int) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public int addTo(char key, int incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public int remove(char key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return 0; + } + hasEmptyKey = false; + int previousValue = values[mask + 1]; + values[mask + 1] = 0; + return previousValue; + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final int previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof CharLookupContainer) { + if (hasEmptyKey && other.contains(((char) 0))) { + hasEmptyKey = false; + values[mask + 1] = 0; + } + + final char[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + char existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (CharCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharIntPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(((char) 0), values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0; + } + } + + final char[] keys = this.keys; + final int[] values = this.values; + for (int slot = 0; slot <= mask; ) { + char existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(((char) 0))) { + hasEmptyKey = false; + values[mask + 1] = 0; + } + } + + final char[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + char existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int get(char key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : 0; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0; + } + } + + /** {@inheritDoc} */ + @Override + public int getOrDefault(char key, int defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(char key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(char key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public int indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public int indexReplace(int index, int newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + int previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, char key, int value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public int indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + int previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, ((char) 0)); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (CharIntCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(CharIntHashMap other) { + if (other.size() != size()) { + return false; + } + + for (CharIntCursor c : other) { + char key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final char[] prevKeys = this.keys; + final int[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final CharIntCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new CharIntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharIntCursor fetch() { + final int mask = CharIntHashMap.this.mask; + while (index <= mask) { + char existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = ((char) 0); + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final char[] keys = this.keys; + final int[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(((char) 0), values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final char[] keys = this.keys; + final int[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(((char) 0), values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { + private final CharIntHashMap owner = CharIntHashMap.this; + + @Override + public boolean contains(char e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((CharIntProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((CharIntPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(CharPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final char e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final CharCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new CharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharCursor fetch() { + final int mask = CharIntHashMap.this.mask; + while (index <= mask) { + char existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = ((char) 0); + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public IntCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractIntCollection { + private final CharIntHashMap owner = CharIntHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(int value) { + for (CharIntCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (CharIntCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (CharIntCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final int e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final IntPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final IntCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new IntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntCursor fetch() { + final int mask = CharIntHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public CharIntHashMap clone() { + try { + + CharIntHashMap cloned = (CharIntHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (CharIntCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static CharIntHashMap from(char[] keys, int[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + CharIntHashMap map = new CharIntHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(char key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(char[] fromKeys, int[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final char[] keys = this.keys; + final int[] values = this.values; + final int mask = this.mask; + char existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + char[] prevKeys = this.keys; + int[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new char[arraySize + emptyElementSlot]); + this.values = (new int[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, char pendingKey, int pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final char[] prevKeys = this.keys; + final int[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final char[] keys = this.keys; + final int[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final char existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = ((char) 0); + values[gapSlot] = 0; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/CharIntMap.java b/src/main/java/com/carrotsearch/hppc/CharIntMap.java new file mode 100755 index 00000000..8c2f24e0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharIntMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.CharIntCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface CharIntMap extends CharIntAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public int get(char key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public int getOrDefault(char key, int defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public int put(char key, int value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(char key, int value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(CharIntAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public int putOrAdd(char key, int putValue, int incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public int addTo(char key, int additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public int remove(char key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link CharIntMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(char key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public int indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public int indexReplace(int index, int newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, char key, int value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public int indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharLongAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/CharLongAssociativeContainer.java new file mode 100755 index 00000000..7999c340 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharLongAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see CharContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface CharLongAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(char key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharLongPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link CharLongProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link CharLongPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public CharCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public LongContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharLongHashMap.java b/src/main/java/com/carrotsearch/hppc/CharLongHashMap.java new file mode 100755 index 00000000..e1bea344 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharLongHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of char to long, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class CharLongHashMap implements CharLongMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public char[] keys; + + /** The array holding values. */ + public long[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public CharLongHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public CharLongHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public CharLongHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public CharLongHashMap(CharLongAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public long put(char key, long value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + long previousValue = hasEmptyKey ? values[mask + 1] : 0L; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final long previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0L; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(CharLongAssociativeContainer container) { + final int count = size(); + for (CharLongCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (CharLongCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public long putOrAdd(char key, long putValue, long incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((long) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public long addTo(char key, long incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public long remove(char key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return 0L; + } + hasEmptyKey = false; + long previousValue = values[mask + 1]; + values[mask + 1] = 0L; + return previousValue; + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final long previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0L; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof CharLookupContainer) { + if (hasEmptyKey && other.contains(((char) 0))) { + hasEmptyKey = false; + values[mask + 1] = 0L; + } + + final char[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + char existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (CharCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharLongPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(((char) 0), values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0L; + } + } + + final char[] keys = this.keys; + final long[] values = this.values; + for (int slot = 0; slot <= mask; ) { + char existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(((char) 0))) { + hasEmptyKey = false; + values[mask + 1] = 0L; + } + } + + final char[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + char existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public long get(char key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : 0L; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0L; + } + } + + /** {@inheritDoc} */ + @Override + public long getOrDefault(char key, long defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(char key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(char key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public long indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public long indexReplace(int index, long newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + long previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, char key, long value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public long indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + long previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0L; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, ((char) 0)); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (CharLongCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(CharLongHashMap other) { + if (other.size() != size()) { + return false; + } + + for (CharLongCursor c : other) { + char key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final char[] prevKeys = this.keys; + final long[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final CharLongCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new CharLongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharLongCursor fetch() { + final int mask = CharLongHashMap.this.mask; + while (index <= mask) { + char existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = ((char) 0); + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final char[] keys = this.keys; + final long[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(((char) 0), values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final char[] keys = this.keys; + final long[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(((char) 0), values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { + private final CharLongHashMap owner = CharLongHashMap.this; + + @Override + public boolean contains(char e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((CharLongProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((CharLongPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(CharPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final char e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final CharCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new CharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharCursor fetch() { + final int mask = CharLongHashMap.this.mask; + while (index <= mask) { + char existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = ((char) 0); + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public LongCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractLongCollection { + private final CharLongHashMap owner = CharLongHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(long value) { + for (CharLongCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (CharLongCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (CharLongCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final long e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final LongPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final LongCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new LongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongCursor fetch() { + final int mask = CharLongHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public CharLongHashMap clone() { + try { + + CharLongHashMap cloned = (CharLongHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (CharLongCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static CharLongHashMap from(char[] keys, long[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + CharLongHashMap map = new CharLongHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(char key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(char[] fromKeys, long[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final char[] keys = this.keys; + final long[] values = this.values; + final int mask = this.mask; + char existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + char[] prevKeys = this.keys; + long[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new char[arraySize + emptyElementSlot]); + this.values = (new long[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, char pendingKey, long pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final char[] prevKeys = this.keys; + final long[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final char[] keys = this.keys; + final long[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final char existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = ((char) 0); + values[gapSlot] = 0L; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/CharLongMap.java b/src/main/java/com/carrotsearch/hppc/CharLongMap.java new file mode 100755 index 00000000..fcbda2b4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharLongMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.CharLongCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface CharLongMap extends CharLongAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public long get(char key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public long getOrDefault(char key, long defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public long put(char key, long value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(char key, long value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(CharLongAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public long putOrAdd(char key, long putValue, long incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public long addTo(char key, long additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public long remove(char key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link CharLongMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(char key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public long indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public long indexReplace(int index, long newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, char key, long value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public long indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharLookupContainer.java b/src/main/java/com/carrotsearch/hppc/CharLookupContainer.java new file mode 100755 index 00000000..3e2fd0a4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharLookupContainer.java @@ -0,0 +1,12 @@ +package com.carrotsearch.hppc; + +/** + * Marker interface for containers that can check if they contain a given object in at least time + * O(log n) and ideally in amortized constant time O(1). + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeLookupContainer.java") +public interface CharLookupContainer extends CharContainer { + public boolean contains(char e); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharObjectAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/CharObjectAssociativeContainer.java new file mode 100755 index 00000000..806efa68 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharObjectAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see CharContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface CharObjectAssociativeContainer extends Iterable> { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator> iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(char key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharObjectPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link CharObjectProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public > T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link CharObjectPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public > T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public CharCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public ObjectContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/CharObjectHashMap.java new file mode 100755 index 00000000..a9d9a0d5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharObjectHashMap.java @@ -0,0 +1,1050 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of char to Object, implemented using open addressing with + * linear probing for collision resolution. Supports null values. + * + * @see HPPC interfaces diagram + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class CharObjectHashMap + implements CharObjectMap, Preallocable, Cloneable, Accountable { + /** The array holding keys. */ + public char[] keys; + + /** The array holding values. */ + public Object[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public CharObjectHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public CharObjectHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public CharObjectHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public CharObjectHashMap(CharObjectAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public VType put(char key, VType value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + VType previousValue = hasEmptyKey ? (VType) values[mask + 1] : null; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final VType previousValue = (VType) values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return null; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(CharObjectAssociativeContainer container) { + final int count = size(); + for (CharObjectCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable> iterable) { + final int count = size(); + for (CharObjectCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** {@inheritDoc} */ + @Override + public VType remove(char key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return null; + } + hasEmptyKey = false; + VType previousValue = (VType) values[mask + 1]; + values[mask + 1] = null; + return previousValue; + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final VType previousValue = (VType) values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return null; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof CharLookupContainer) { + if (hasEmptyKey && other.contains(((char) 0))) { + hasEmptyKey = false; + values[mask + 1] = null; + } + + final char[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + char existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (CharCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharObjectPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(((char) 0), (VType) values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = null; + } + } + + final char[] keys = this.keys; + final VType[] values = (VType[]) this.values; + for (int slot = 0; slot <= mask; ) { + char existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(((char) 0))) { + hasEmptyKey = false; + values[mask + 1] = null; + } + } + + final char[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + char existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public VType get(char key) { + if (((key) == 0)) { + return hasEmptyKey ? (VType) values[mask + 1] : null; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return (VType) values[slot]; + } + slot = (slot + 1) & mask; + } + + return null; + } + } + + /** {@inheritDoc} */ + @Override + public VType getOrDefault(char key, VType defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? (VType) values[mask + 1] : defaultValue; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return (VType) values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(char key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(char key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public VType indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return (VType) values[index]; + } + + /** {@inheritDoc} */ + @Override + public VType indexReplace(int index, VType newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + VType previousValue = (VType) values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, char key, VType value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public VType indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + VType previousValue = (VType) values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = null; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, ((char) 0)); + + Arrays.fill(values, null); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (CharObjectCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** + * Return true if all keys of some other container exist in this container. Values are compared + * using {@link Objects#equals(Object)} method. + */ + protected boolean equalElements(CharObjectHashMap other) { + if (other.size() != size()) { + return false; + } + + for (CharObjectCursor c : other) { + char key = c.key; + if (!containsKey(key) || !java.util.Objects.equals(c.value, get(key))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final char[] prevKeys = this.keys; + final VType[] prevValues = (VType[]) this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final CharObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new CharObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharObjectCursor fetch() { + final int mask = CharObjectHashMap.this.mask; + while (index <= mask) { + char existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = (VType) values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = ((char) 0); + cursor.value = (VType) values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator> iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T procedure) { + final char[] keys = this.keys; + final VType[] values = (VType[]) this.values; + + if (hasEmptyKey) { + procedure.apply(((char) 0), (VType) values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T predicate) { + final char[] keys = this.keys; + final VType[] values = (VType[]) this.values; + + if (hasEmptyKey) { + if (!predicate.apply(((char) 0), (VType) values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { + private final CharObjectHashMap owner = CharObjectHashMap.this; + + @Override + public boolean contains(char e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((CharObjectProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((CharObjectPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(CharPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final char e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final CharCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new CharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharCursor fetch() { + final int mask = CharObjectHashMap.this.mask; + while (index <= mask) { + char existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = ((char) 0); + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public ObjectCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractObjectCollection { + private final CharObjectHashMap owner = CharObjectHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(VType value) { + for (CharObjectCursor c : owner) { + if (java.util.Objects.equals(value, c.value)) { + return true; + } + } + return false; + } + + @Override + public > T forEach(T procedure) { + for (CharObjectCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public > T forEach(T predicate) { + for (CharObjectCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator> iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final VType e) { + return owner.removeAll((key, value) -> java.util.Objects.equals(e, value)); + } + + @Override + public int removeAll(final ObjectPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator> { + private final ObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new ObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectCursor fetch() { + final int mask = CharObjectHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = (VType) values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = (VType) values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public CharObjectHashMap clone() { + try { + + CharObjectHashMap cloned = (CharObjectHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (CharObjectCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static CharObjectHashMap from(char[] keys, VType[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + CharObjectHashMap map = new CharObjectHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(char key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(char[] fromKeys, VType[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final char[] keys = this.keys; + final VType[] values = (VType[]) this.values; + final int mask = this.mask; + char existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + char[] prevKeys = this.keys; + VType[] prevValues = (VType[]) this.values; + try { + int emptyElementSlot = 1; + this.keys = (new char[arraySize + emptyElementSlot]); + this.values = ((VType[]) new Object[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, char pendingKey, VType pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final char[] prevKeys = this.keys; + final VType[] prevValues = (VType[]) this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final char[] keys = this.keys; + final VType[] values = (VType[]) this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final char existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = ((char) 0); + values[gapSlot] = null; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/CharObjectMap.java b/src/main/java/com/carrotsearch/hppc/CharObjectMap.java new file mode 100755 index 00000000..6a1004df --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharObjectMap.java @@ -0,0 +1,181 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.CharObjectCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface CharObjectMap extends CharObjectAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public VType get(char key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public VType getOrDefault(char key, VType defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public VType put(char key, VType value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(char key, VType value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(CharObjectAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable> iterable); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public VType remove(char key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link CharObjectMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(char key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public VType indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public VType indexReplace(int index, VType newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, char key, VType value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public VType indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharSet.java b/src/main/java/com/carrotsearch/hppc/CharSet.java new file mode 100755 index 00000000..a9740eac --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharSet.java @@ -0,0 +1,33 @@ +package com.carrotsearch.hppc; + +/** A set of chars. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeSet.java") +public interface CharSet extends CharCollection { + /** + * Adds k to the set. + * + * @return Returns true if this element was not part of the set before. Returns + * false if an equal element is already part of the set, does not replace the + * existing element with the argument. + */ + public boolean add(char k); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); + + /** + * Adds all elements from the given {@link CharContainer} to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + * @since 0.9.1 + */ + public int addAll(CharContainer container); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharShortAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/CharShortAssociativeContainer.java new file mode 100755 index 00000000..66f6c444 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharShortAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see CharContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface CharShortAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(char key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(CharShortPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link CharShortProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link CharShortPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public CharCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public ShortContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharShortHashMap.java b/src/main/java/com/carrotsearch/hppc/CharShortHashMap.java new file mode 100755 index 00000000..686281c6 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharShortHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of char to short, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class CharShortHashMap implements CharShortMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public char[] keys; + + /** The array holding values. */ + public short[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public CharShortHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public CharShortHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public CharShortHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public CharShortHashMap(CharShortAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public short put(char key, short value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + short previousValue = hasEmptyKey ? values[mask + 1] : ((short) 0); + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final short previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return ((short) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(CharShortAssociativeContainer container) { + final int count = size(); + for (CharShortCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (CharShortCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public short putOrAdd(char key, short putValue, short incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((short) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public short addTo(char key, short incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public short remove(char key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return ((short) 0); + } + hasEmptyKey = false; + short previousValue = values[mask + 1]; + values[mask + 1] = ((short) 0); + return previousValue; + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final short previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return ((short) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof CharLookupContainer) { + if (hasEmptyKey && other.contains(((char) 0))) { + hasEmptyKey = false; + values[mask + 1] = ((short) 0); + } + + final char[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + char existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (CharCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharShortPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(((char) 0), values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = ((short) 0); + } + } + + final char[] keys = this.keys; + final short[] values = this.values; + for (int slot = 0; slot <= mask; ) { + char existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(((char) 0))) { + hasEmptyKey = false; + values[mask + 1] = ((short) 0); + } + } + + final char[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + char existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public short get(char key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : ((short) 0); + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return ((short) 0); + } + } + + /** {@inheritDoc} */ + @Override + public short getOrDefault(char key, short defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(char key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(char key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public short indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public short indexReplace(int index, short newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + short previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, char key, short value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public short indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + short previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = ((short) 0); + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, ((char) 0)); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (CharShortCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(CharShortHashMap other) { + if (other.size() != size()) { + return false; + } + + for (CharShortCursor c : other) { + char key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final char[] prevKeys = this.keys; + final short[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final CharShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new CharShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharShortCursor fetch() { + final int mask = CharShortHashMap.this.mask; + while (index <= mask) { + char existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = ((char) 0); + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final char[] keys = this.keys; + final short[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(((char) 0), values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final char[] keys = this.keys; + final short[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(((char) 0), values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { + private final CharShortHashMap owner = CharShortHashMap.this; + + @Override + public boolean contains(char e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((CharShortProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((CharShortPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(CharPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final char e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final CharCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new CharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharCursor fetch() { + final int mask = CharShortHashMap.this.mask; + while (index <= mask) { + char existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = ((char) 0); + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public ShortCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractShortCollection { + private final CharShortHashMap owner = CharShortHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(short value) { + for (CharShortCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (CharShortCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (CharShortCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final short e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final ShortPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new ShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortCursor fetch() { + final int mask = CharShortHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public CharShortHashMap clone() { + try { + + CharShortHashMap cloned = (CharShortHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (CharShortCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static CharShortHashMap from(char[] keys, short[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + CharShortHashMap map = new CharShortHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(char key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(char[] fromKeys, short[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final char[] keys = this.keys; + final short[] values = this.values; + final int mask = this.mask; + char existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + char[] prevKeys = this.keys; + short[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new char[arraySize + emptyElementSlot]); + this.values = (new short[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, char pendingKey, short pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final char[] prevKeys = this.keys; + final short[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final char[] keys = this.keys; + final short[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final char existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = ((char) 0); + values[gapSlot] = ((short) 0); + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/CharShortMap.java b/src/main/java/com/carrotsearch/hppc/CharShortMap.java new file mode 100755 index 00000000..e5b0deeb --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharShortMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.CharShortCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface CharShortMap extends CharShortAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public short get(char key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public short getOrDefault(char key, short defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public short put(char key, short value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(char key, short value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(CharShortAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public short putOrAdd(char key, short putValue, short incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public short addTo(char key, short additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public short remove(char key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link CharShortMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(char key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public short indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public short indexReplace(int index, short newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, char key, short value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public short indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharStack.java b/src/main/java/com/carrotsearch/hppc/CharStack.java new file mode 100755 index 00000000..fb7a5947 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharStack.java @@ -0,0 +1,137 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.CharCursor; + +/** + * A subclass of {@link CharArrayList} adding stack-related utility methods. The top of the stack is + * at the {@link #size()} - 1 element. + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java") +public class CharStack extends CharArrayList { + /** New instance with sane defaults. */ + public CharStack() { + super(); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public CharStack(int expectedElements) { + super(expectedElements); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public CharStack(int expectedElements, ArraySizingStrategy resizer) { + super(expectedElements, resizer); + } + + /** Create a stack by pushing all elements of another container to it. */ + public CharStack(CharContainer container) { + super(container); + } + + /** Adds one char to the stack. */ + public void push(char e1) { + ensureBufferSpace(1); + buffer[elementsCount++] = e1; + } + + /** Adds two chars to the stack. */ + public void push(char e1, char e2) { + ensureBufferSpace(2); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + } + + /** Adds three chars to the stack. */ + public void push(char e1, char e2, char e3) { + ensureBufferSpace(3); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + buffer[elementsCount++] = e3; + } + + /** Adds four chars to the stack. */ + public void push(char e1, char e2, char e3, char e4) { + ensureBufferSpace(4); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + buffer[elementsCount++] = e3; + buffer[elementsCount++] = e4; + } + + /** Add a range of array elements to the stack. */ + public void push(char[] elements, int start, int len) { + assert start >= 0 && len >= 0; + + ensureBufferSpace(len); + System.arraycopy(elements, start, buffer, elementsCount, len); + elementsCount += len; + } + + /** + * Vararg-signature method for pushing elements at the top of the stack. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + */ + public final void push(char... elements) { + push(elements, 0, elements.length); + } + + /** Pushes all elements from another container to the top of the stack. */ + public int pushAll(CharContainer container) { + return addAll(container); + } + + /** Pushes all elements from another iterable to the top of the stack. */ + public int pushAll(Iterable iterable) { + return addAll(iterable); + } + + /** Discard an arbitrary number of elements from the top of the stack. */ + public void discard(int count) { + assert elementsCount >= count; + + elementsCount -= count; + } + + /** Discard the top element from the stack. */ + public void discard() { + assert elementsCount > 0; + + elementsCount--; + } + + /** Remove the top element from the stack and return it. */ + public char pop() { + return removeLast(); + } + + /** Peek at the top element on the stack. */ + public char peek() { + assert elementsCount > 0; + return buffer[elementsCount - 1]; + } + + /** Create a stack by pushing a variable number of arguments to it. */ + public static CharStack from(char... elements) { + final CharStack stack = new CharStack(elements.length); + stack.push(elements); + return stack; + } + + /** {@inheritDoc} */ + @Override + public CharStack clone() { + return (CharStack) super.clone(); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/Containers.java b/src/main/java/com/carrotsearch/hppc/Containers.java new file mode 100755 index 00000000..edd41b7c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/Containers.java @@ -0,0 +1,68 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.internals.SuppressForbidden; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Constants used as defaults in containers. + * + * @see HashContainers + */ +public final class Containers { + /** The default number of expected elements for containers. */ + public static final int DEFAULT_EXPECTED_ELEMENTS = 4; + + /** + * External initial seed value. We do not care about multiple assignments so not volatile. + * + * @see #randomSeed64() + */ + private static String testsSeedProperty; + + /** Unique marker for {@link #testsSeedProperty}. */ + private static final String NOT_AVAILABLE = new String(); + + private Containers() {} + + /** + * Provides a (possibly) random initial seed for randomized stuff. + * + *

If tests.seed property is available and accessible, the returned value will be + * derived from the value of that property and will be constant to ensure reproducibility in + * presence of the randomized testing package. + * + * @see "https://github.com/carrotsearch/randomizedtesting" + */ + @SuppressForbidden + public static long randomSeed64() { + if (testsSeedProperty == null) { + testsSeedProperty = System.getProperty("tests.seed", NOT_AVAILABLE); + } + + long initialSeed; + if (testsSeedProperty != NOT_AVAILABLE) { + initialSeed = testsSeedProperty.hashCode(); + } else { + // Mix something that is changing over time (nanoTime) + // ... with something that is thread-local and relatively unique + // even for very short time-spans (new Object's address from a TLAB). + initialSeed = System.nanoTime() ^ System.identityHashCode(new Object()); + } + return BitMixer.mix64(initialSeed); + } + + /** Reset state for tests. */ + static void test$reset() { + testsSeedProperty = null; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/DoubleArrayDeque.java b/src/main/java/com/carrotsearch/hppc/DoubleArrayDeque.java new file mode 100755 index 00000000..7561da28 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoubleArrayDeque.java @@ -0,0 +1,776 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; + +import com.carrotsearch.hppc.cursors.DoubleCursor; +import com.carrotsearch.hppc.predicates.DoublePredicate; +import com.carrotsearch.hppc.procedures.DoubleProcedure; +import java.util.*; + +/** An array-backed {@link DoubleDeque}. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java") +public class DoubleArrayDeque extends AbstractDoubleCollection + implements DoubleDeque, Preallocable, Cloneable, Accountable { + + /** Reuse the same strategy instance. */ + private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = + BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; + + /** Internal array for storing elements of the deque. */ + public double[] buffer = DoubleArrayList.EMPTY_ARRAY; + + /** + * The index of the element at the head of the deque or an arbitrary number equal to tail if the + * deque is empty. + */ + public int head; + + /** The index at which the next element would be added to the tail of the deque. */ + public int tail; + + /** Buffer resizing strategy. */ + protected final ArraySizingStrategy resizer; + + /** New instance with sane defaults. */ + public DoubleArrayDeque() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public DoubleArrayDeque(int expectedElements) { + this(expectedElements, DEFAULT_SIZING_STRATEGY); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public DoubleArrayDeque(int expectedElements, ArraySizingStrategy resizer) { + assert resizer != null; + this.resizer = resizer; + ensureCapacity(expectedElements); + } + + /** + * Creates a new deque from elements of another container, appending elements at the end of the + * deque in the iteration order. + */ + public DoubleArrayDeque(DoubleContainer container) { + this(container.size()); + addLast(container); + } + + /** {@inheritDoc} */ + @Override + public void addFirst(double e1) { + int h = oneLeft(head, buffer.length); + if (h == tail) { + ensureBufferSpace(1); + h = oneLeft(head, buffer.length); + } + buffer[head = h] = e1; + } + + /** + * Vararg-signature method for adding elements at the front of this deque. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + * + * @param elements The elements to add. + */ + public final void addFirst(double... elements) { + ensureBufferSpace(elements.length); + for (double k : elements) { + addFirst(k); + } + } + + /** + * Inserts all elements from the given container to the front of this deque. + * + * @param container The container to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addFirst(DoubleContainer container) { + int size = container.size(); + ensureBufferSpace(size); + + for (DoubleCursor cursor : container) { + addFirst(cursor.value); + } + + return size; + } + + /** + * Inserts all elements from the given iterable to the front of this deque. + * + * @param iterable The iterable to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addFirst(Iterable iterable) { + int size = 0; + for (DoubleCursor cursor : iterable) { + addFirst(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public void addLast(double e1) { + int t = oneRight(tail, buffer.length); + if (head == t) { + ensureBufferSpace(1); + t = oneRight(tail, buffer.length); + } + buffer[tail] = e1; + tail = t; + } + + /** + * Vararg-signature method for adding elements at the end of this deque. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + * + * @param elements The elements to iterate over. + */ + public final void addLast(double... elements) { + ensureBufferSpace(1); + for (double k : elements) { + addLast(k); + } + } + + /** + * Inserts all elements from the given container to the end of this deque. + * + * @param container The container to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addLast(DoubleContainer container) { + int size = container.size(); + ensureBufferSpace(size); + + for (DoubleCursor cursor : container) { + addLast(cursor.value); + } + + return size; + } + + /** + * Inserts all elements from the given iterable to the end of this deque. + * + * @param iterable The iterable to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addLast(Iterable iterable) { + int size = 0; + for (DoubleCursor cursor : iterable) { + addLast(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public double removeFirst() { + assert size() > 0 : "The deque is empty."; + + final double result = buffer[head]; + buffer[head] = 0d; + head = oneRight(head, buffer.length); + return result; + } + + /** {@inheritDoc} */ + @Override + public double removeLast() { + assert size() > 0 : "The deque is empty."; + + tail = oneLeft(tail, buffer.length); + final double result = buffer[tail]; + buffer[tail] = 0d; + return result; + } + + /** {@inheritDoc} */ + @Override + public double getFirst() { + assert size() > 0 : "The deque is empty."; + + return buffer[head]; + } + + /** {@inheritDoc} */ + @Override + public double getLast() { + assert size() > 0 : "The deque is empty."; + + return buffer[oneLeft(tail, buffer.length)]; + } + + /** {@inheritDoc} */ + @Override + public int removeFirst(double e1) { + final int index = bufferIndexOf(e1); + if (index >= 0) removeAtBufferIndex(index); + return index; + } + + /** + * Return the index of the first (counting from head) element equal to e1. The index + * points to the {@link #buffer} array. + * + * @param e1 The element to look for. + * @return Returns the index of the first element equal to e1 or -1 if + * not found. + */ + public int bufferIndexOf(double e1) { + final int last = tail; + final int bufLen = buffer.length; + for (int i = head; i != last; i = oneRight(i, bufLen)) { + if ((Double.doubleToLongBits(e1) == Double.doubleToLongBits(buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int removeLast(double e1) { + final int index = lastBufferIndexOf(e1); + if (index >= 0) { + removeAtBufferIndex(index); + } + return index; + } + + /** + * Return the index of the last (counting from tail) element equal to e1. The index + * points to the {@link #buffer} array. + * + * @param e1 The element to look for. + * @return Returns the index of the first element equal to e1 or -1 if + * not found. + */ + public int lastBufferIndexOf(double e1) { + final int bufLen = buffer.length; + final int last = oneLeft(head, bufLen); + for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) { + if ((Double.doubleToLongBits(e1) == Double.doubleToLongBits(buffer[i]))) return i; + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(double e1) { + int removed = 0; + final int last = tail; + final int bufLen = buffer.length; + int from, to; + for (from = to = head; from != last; from = oneRight(from, bufLen)) { + if ((Double.doubleToLongBits(e1) == Double.doubleToLongBits(buffer[from]))) { + buffer[from] = 0d; + removed++; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0d; + } + + to = oneRight(to, bufLen); + } + + tail = to; + return removed; + } + + /** + * Removes the element at index in the internal {#link {@link #buffer} array, + * returning its value. + * + * @param index Index of the element to remove. The index must be located between {@link #head} + * and {@link #tail} in modulo {@link #buffer} arithmetic. + */ + public void removeAtBufferIndex(int index) { + assert (head <= tail ? index >= head && index < tail : index >= head || index < tail) + : "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ")."; + + // Cache fields in locals (hopefully moved to registers). + final double[] buffer = this.buffer; + final int bufLen = buffer.length; + final int lastIndex = bufLen - 1; + final int head = this.head; + final int tail = this.tail; + + final int leftChunk = Math.abs(index - head) % bufLen; + final int rightChunk = Math.abs(tail - index) % bufLen; + + if (leftChunk < rightChunk) { + if (index >= head) { + System.arraycopy(buffer, head, buffer, head + 1, leftChunk); + } else { + System.arraycopy(buffer, 0, buffer, 1, index); + buffer[0] = buffer[lastIndex]; + System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head); + } + buffer[head] = 0d; + this.head = oneRight(head, bufLen); + } else { + if (index < tail) { + System.arraycopy(buffer, index + 1, buffer, index, rightChunk); + } else { + System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index); + buffer[lastIndex] = buffer[0]; + System.arraycopy(buffer, 1, buffer, 0, tail); + } + buffer[tail] = 0d; + this.tail = oneLeft(tail, bufLen); + } + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int size() { + if (head <= tail) return tail - head; + else return (tail - head + buffer.length); + } + + /** + * {@inheritDoc} + * + *

The internal array buffers are not released as a result of this call. + * + * @see #release() + */ + @Override + public void clear() { + if (head < tail) { + Arrays.fill(buffer, head, tail, 0d); + } else { + Arrays.fill(buffer, 0, tail, 0d); + Arrays.fill(buffer, head, buffer.length, 0d); + } + this.head = tail = 0; + } + + /** Release internal buffers of this deque and reallocate with the default buffer. */ + public void release() { + this.head = tail = 0; + buffer = DoubleArrayList.EMPTY_ARRAY; + ensureBufferSpace(0); + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + ensureBufferSpace(expectedElements - size()); + } + + /** + * Ensures the internal buffer has enough free slots to store expectedAdditions. + * Increases internal buffer size if needed. + */ + protected void ensureBufferSpace(int expectedAdditions) { + final int bufferLen = buffer.length; + final int elementsCount = size(); + + if (elementsCount + expectedAdditions >= bufferLen) { + final int emptySlot = 1; // deque invariant: always an empty slot. + final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions); + assert newSize >= (elementsCount + expectedAdditions + emptySlot) + : "Resizer failed to" + + " return sensible new size: " + + newSize + + " <= " + + (elementsCount + expectedAdditions); + + try { + final double[] newBuffer = (new double[newSize]); + if (bufferLen > 0) { + toArray(newBuffer); + tail = elementsCount; + head = 0; + } + this.buffer = newBuffer; + } catch (OutOfMemoryError e) { + throw new BufferAllocationException( + "Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize); + } + } + } + + /** {@inheritDoc} */ + @Override + public double[] toArray() { + + final int size = size(); + return toArray((new double[size])); + } + + /** + * Copies elements of this deque to an array. The content of the target array is + * filled from index 0 (head of the queue) to index size() - 1 (tail of the queue). + * + * @param target The target array must be large enough to hold all elements. + * @return Returns the target argument for chaining. + */ + public double[] toArray(double[] target) { + assert target.length >= size() : "Target array must be >= " + size(); + + if (head < tail) { + // The contents is not wrapped around. Just copy. + System.arraycopy(buffer, head, target, 0, size()); + } else if (head > tail) { + // The contents is split. Merge elements from the following indexes: + // [head...buffer.length - 1][0, tail - 1] + final int rightCount = buffer.length - head; + System.arraycopy(buffer, head, target, 0, rightCount); + System.arraycopy(buffer, 0, target, rightCount, tail); + } + + return target; + } + + /** + * Clone this object. The returned clone will reuse the same hash function and array resizing + * strategy. + */ + @Override + public DoubleArrayDeque clone() { + try { + + DoubleArrayDeque cloned = (DoubleArrayDeque) super.clone(); + cloned.buffer = buffer.clone(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Move one index to the left, wrapping around buffer. */ + protected static int oneLeft(int index, int modulus) { + if (index >= 1) { + return index - 1; + } + return modulus - 1; + } + + /** Move one index to the right, wrapping around buffer. */ + protected static int oneRight(int index, int modulus) { + if (index + 1 == modulus) { + return 0; + } + return index + 1; + } + + @Override + public long ramBytesAllocated() { + // int: head, tail + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES * 2 + + resizer.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(buffer); + } + + @Override + public long ramBytesUsed() { + // int: head, tail + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES * 2 + + resizer.ramBytesUsed() + + RamUsageEstimator.shallowUsedSizeOfArray(buffer, size()); + } + + /** An iterator implementation for {@link ObjectArrayDeque#iterator}. */ + private final class ValueIterator extends AbstractIterator { + private final DoubleCursor cursor; + private int remaining; + + public ValueIterator() { + cursor = new DoubleCursor(); + cursor.index = oneLeft(head, buffer.length); + this.remaining = size(); + } + + @Override + protected DoubleCursor fetch() { + if (remaining == 0) { + return done(); + } + + remaining--; + cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)]; + return cursor; + } + } + + /** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */ + private final class DescendingValueIterator extends AbstractIterator { + private final DoubleCursor cursor; + private int remaining; + + public DescendingValueIterator() { + cursor = new DoubleCursor(); + cursor.index = tail; + this.remaining = size(); + } + + @Override + protected DoubleCursor fetch() { + if (remaining == 0) return done(); + + remaining--; + cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)]; + return cursor; + } + } + + /** + * Returns a cursor over the values of this deque (in head to tail order). The iterator is + * implemented as a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in + * the deque's buffer) use the cursor's public fields. An example is shown below. + * + *

+   * for (IntValueCursor c : intDeque) {
+   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator iterator() { + return new ValueIterator(); + } + + /** + * Returns a cursor over the values of this deque (in tail to head order). The iterator is + * implemented as a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in + * the deque's buffer) use the cursor's public fields. An example is shown below. + * + *
+   * for (Iterator<IntCursor> i = intDeque.descendingIterator(); i.hasNext();) {
+   *   final IntCursor c = i.next();
+   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator descendingIterator() { + return new DescendingValueIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + forEach(procedure, head, tail); + return procedure; + } + + /** + * Applies procedure to a slice of the deque, fromIndex, inclusive, to + * toIndex, exclusive. + */ + private void forEach(DoubleProcedure procedure, int fromIndex, final int toIndex) { + final double[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + procedure.apply(buffer[i]); + } + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + int fromIndex = head; + int toIndex = tail; + + final double[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + if (!predicate.apply(buffer[i])) { + break; + } + } + + return predicate; + } + + /** Applies procedure to all elements of this deque, tail to head. */ + @Override + public T descendingForEach(T procedure) { + descendingForEach(procedure, head, tail); + return procedure; + } + + /** + * Applies procedure to a slice of the deque, toIndex, exclusive, down + * to fromIndex, inclusive. + */ + private void descendingForEach(DoubleProcedure procedure, int fromIndex, final int toIndex) { + if (fromIndex == toIndex) return; + + final double[] buffer = this.buffer; + int i = toIndex; + do { + i = oneLeft(i, buffer.length); + procedure.apply(buffer[i]); + } while (i != fromIndex); + } + + /** {@inheritDoc} */ + @Override + public T descendingForEach(T predicate) { + descendingForEach(predicate, head, tail); + return predicate; + } + + /** + * Applies predicate to a slice of the deque, toIndex, exclusive, down + * to fromIndex, inclusive or until the predicate returns false. + */ + private void descendingForEach(DoublePredicate predicate, int fromIndex, final int toIndex) { + if (fromIndex == toIndex) return; + + final double[] buffer = this.buffer; + int i = toIndex; + do { + i = oneLeft(i, buffer.length); + if (!predicate.apply(buffer[i])) { + break; + } + } while (i != fromIndex); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(DoublePredicate predicate) { + final double[] buffer = this.buffer; + final int last = tail; + final int bufLen = buffer.length; + int removed = 0; + int from, to; + from = to = head; + try { + for (from = to = head; from != last; from = oneRight(from, bufLen)) { + if (predicate.apply(buffer[from])) { + buffer[from] = 0d; + removed++; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0d; + } + + to = oneRight(to, bufLen); + } + } finally { + // Keep the deque in consistent state even if the predicate throws an exception. + for (; from != last; from = oneRight(from, bufLen)) { + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0d; + } + + to = oneRight(to, bufLen); + } + tail = to; + } + + return removed; + } + + /** {@inheritDoc} */ + @Override + public boolean contains(double e) { + int fromIndex = head; + int toIndex = tail; + + final double[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + if ((Double.doubleToLongBits(e) == Double.doubleToLongBits(buffer[i]))) { + return true; + } + } + + return false; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 1; + int fromIndex = head; + int toIndex = tail; + + final double[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + h = 31 * h + BitMixer.mix(this.buffer[i]); + } + return h; + } + + /** + * Returns true only if the other object is an instance of the same class and with + * the same elements. + */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Compare order-aligned elements against another {@link DoubleDeque}. */ + protected boolean equalElements(DoubleArrayDeque other) { + int max = size(); + if (other.size() != max) { + return false; + } + + Iterator i1 = this.iterator(); + Iterator i2 = other.iterator(); + + while (i1.hasNext() && i2.hasNext()) { + if (!(Double.doubleToLongBits(i1.next().value) == Double.doubleToLongBits(i2.next().value))) { + return false; + } + } + + return !i1.hasNext() && !i2.hasNext(); + } + + /** Create a new deque by pushing a variable number of arguments to the end of it. */ + public static DoubleArrayDeque from(double... elements) { + final DoubleArrayDeque coll = new DoubleArrayDeque(elements.length); + coll.addLast(elements); + return coll; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/DoubleArrayList.java b/src/main/java/com/carrotsearch/hppc/DoubleArrayList.java new file mode 100755 index 00000000..a0a8bbdd --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoubleArrayList.java @@ -0,0 +1,586 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.DoublePredicate; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; +import java.util.stream.DoubleStream; + +/** An array-backed list of doubles. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java") +public class DoubleArrayList extends AbstractDoubleCollection + implements DoubleIndexedContainer, Preallocable, Cloneable, Accountable { + /** An immutable empty buffer (array). */ + public static final double[] EMPTY_ARRAY = new double[0]; + + ; + + /** Reuse the same strategy instance. */ + private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = + BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; + + /** + * Internal array for storing the list. The array may be larger than the current size ({@link + * #size()}). + */ + public double[] buffer = EMPTY_ARRAY; + + /** Current number of elements stored in {@link #buffer}. */ + public int elementsCount; + + /** Buffer resizing strategy. */ + protected final ArraySizingStrategy resizer; + + /** New instance with sane defaults. */ + public DoubleArrayList() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public DoubleArrayList(int expectedElements) { + this(expectedElements, DEFAULT_SIZING_STRATEGY); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public DoubleArrayList(int expectedElements, ArraySizingStrategy resizer) { + assert resizer != null; + this.resizer = resizer; + buffer = Arrays.copyOf(buffer, expectedElements); + } + + /** Creates a new list from the elements of another container in its iteration order. */ + public DoubleArrayList(DoubleContainer container) { + this(container.size()); + addAll(container); + } + + /** {@inheritDoc} */ + @Override + public void add(double e1) { + ensureBufferSpace(1); + buffer[elementsCount++] = e1; + } + + /** + * Appends two elements at the end of the list. To add more than two elements, use add + * (vararg-version) or access the buffer directly (tight loop). + */ + public void add(double e1, double e2) { + ensureBufferSpace(2); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + } + + /** Add all elements from a range of given array to the list. */ + public void add(double[] elements, int start, int length) { + assert length >= 0 : "Length must be >= 0"; + + ensureBufferSpace(length); + System.arraycopy(elements, start, buffer, elementsCount, length); + elementsCount += length; + } + + /** + * Vararg-signature method for adding elements at the end of the list. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + */ + public final void add(double... elements) { + add(elements, 0, elements.length); + } + + /** Adds all elements from another container. */ + public int addAll(DoubleContainer container) { + final int size = container.size(); + ensureBufferSpace(size); + + for (DoubleCursor cursor : container) { + add(cursor.value); + } + + return size; + } + + /** Adds all elements from another iterable. */ + public int addAll(Iterable iterable) { + int size = 0; + for (DoubleCursor cursor : iterable) { + add(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public void insert(int index, double e1) { + assert (index >= 0 && index <= size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + "]."; + + ensureBufferSpace(1); + System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index); + buffer[index] = e1; + elementsCount++; + } + + /** {@inheritDoc} */ + @Override + public double get(int index) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + return buffer[index]; + } + + /** {@inheritDoc} */ + @Override + public double set(int index, double e1) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + final double v = buffer[index]; + buffer[index] = e1; + return v; + } + + /** {@inheritDoc} */ + @Override + public double removeAt(int index) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + final double v = buffer[index]; + System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index); + + return v; + } + + /** {@inheritDoc} */ + @Override + public double removeLast() { + assert elementsCount > 0; + + final double v = buffer[--elementsCount]; + + return v; + } + + /** {@inheritDoc} */ + @Override + public void removeRange(int fromIndex, int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex); + final int count = toIndex - fromIndex; + elementsCount -= count; + } + + /** {@inheritDoc} */ + @Override + public boolean removeElement(double e1) { + return removeFirst(e1) != -1; + } + + /** {@inheritDoc} */ + @Override + public int removeFirst(double e1) { + final int index = indexOf(e1); + if (index >= 0) removeAt(index); + return index; + } + + /** {@inheritDoc} */ + @Override + public int removeLast(double e1) { + final int index = lastIndexOf(e1); + if (index >= 0) removeAt(index); + return index; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(double e1) { + int to = 0; + for (int from = 0; from < elementsCount; from++) { + if ((Double.doubleToLongBits(e1) == Double.doubleToLongBits(buffer[from]))) { + continue; + } + if (to != from) { + buffer[to] = buffer[from]; + } + to++; + } + final int deleted = elementsCount - to; + this.elementsCount = to; + + return deleted; + } + + /** {@inheritDoc} */ + @Override + public boolean contains(double e1) { + return indexOf(e1) >= 0; + } + + /** {@inheritDoc} */ + @Override + public int indexOf(double e1) { + for (int i = 0; i < elementsCount; i++) { + if ((Double.doubleToLongBits(e1) == Double.doubleToLongBits(buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int lastIndexOf(double e1) { + for (int i = elementsCount - 1; i >= 0; i--) { + if ((Double.doubleToLongBits(e1) == Double.doubleToLongBits(buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return elementsCount == 0; + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + final int bufferLen = (buffer == null ? 0 : buffer.length); + if (expectedElements > bufferLen) { + ensureBufferSpace(expectedElements - size()); + } + } + + /** + * Ensures the internal buffer has enough free slots to store expectedAdditions. + * Increases internal buffer size if needed. + */ + protected void ensureBufferSpace(int expectedAdditions) { + final int bufferLen = (buffer == null ? 0 : buffer.length); + if (elementsCount + expectedAdditions > bufferLen) { + final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions); + assert newSize >= elementsCount + expectedAdditions + : "Resizer failed to" + + " return sensible new size: " + + newSize + + " <= " + + (elementsCount + expectedAdditions); + + this.buffer = Arrays.copyOf(buffer, newSize); + } + } + + /** + * Truncate or expand the list to the new size. If the list is truncated, the buffer will not be + * reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated + * values will be reset to the default value (zero). If the list is expanded, the elements beyond + * the current size are initialized with JVM-defaults (zero or null values). + */ + public void resize(int newSize) { + if (newSize <= buffer.length) { + if (newSize < elementsCount) { + Arrays.fill(buffer, newSize, elementsCount, 0d); + } else { + Arrays.fill(buffer, elementsCount, newSize, 0d); + } + } else { + ensureCapacity(newSize); + } + this.elementsCount = newSize; + } + + /** {@inheritDoc} */ + @Override + public int size() { + return elementsCount; + } + + /** Trim the internal buffer to the current size. */ + public void trimToSize() { + if (size() != this.buffer.length) { + this.buffer = toArray(); + } + } + + /** + * Sets the number of stored elements to zero. Releases and initializes the internal storage array + * to default values. To clear the list without cleaning the buffer, simply set the {@link + * #elementsCount} field to zero. + */ + @Override + public void clear() { + Arrays.fill(buffer, 0, elementsCount, 0d); + this.elementsCount = 0; + } + + /** Sets the number of stored elements to zero and releases the internal storage array. */ + @Override + public void release() { + this.buffer = EMPTY_ARRAY; + this.elementsCount = 0; + } + + /** + * {@inheritDoc} + * + *

The returned array is sized to match exactly the number of elements of the stack. + */ + @Override + public double[] toArray() { + + return Arrays.copyOf(buffer, elementsCount); + } + + @Override + public DoubleStream stream() { + + return Arrays.stream(buffer, 0, size()); + } + + /** {@inheritDoc} */ + @Override + public DoubleIndexedContainer sort() { + Arrays.sort(buffer, 0, elementsCount); + return this; + } + + /** {@inheritDoc} */ + @Override + public DoubleIndexedContainer reverse() { + for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) { + double tmp = buffer[i]; + buffer[i] = buffer[j]; + buffer[j] = tmp; + } + return this; + } + + /** + * Clone this object. The returned clone will reuse the same hash function and array resizing + * strategy. + */ + @Override + public DoubleArrayList clone() { + try { + + final DoubleArrayList cloned = (DoubleArrayList) super.clone(); + cloned.buffer = buffer.clone(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 1, max = elementsCount; + for (int i = 0; i < max; i++) { + h = 31 * h + BitMixer.mix(this.buffer[i]); + } + return h; + } + + /** + * Returns true only if the other object is an instance of the same class and with + * the same elements. + */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Compare index-aligned elements against another {@link DoubleIndexedContainer}. */ + protected boolean equalElements(DoubleArrayList other) { + int max = size(); + if (other.size() != max) { + return false; + } + + for (int i = 0; i < max; i++) { + if (!(Double.doubleToLongBits(get(i)) == Double.doubleToLongBits(other.get(i)))) { + return false; + } + } + + return true; + } + + @Override + public long ramBytesAllocated() { + // int: elementsCount + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES + + resizer.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(buffer); + } + + @Override + public long ramBytesUsed() { + // int: elementsCount + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES + + resizer.ramBytesUsed() + + RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount); + } + + /** An iterator implementation for {@link DoubleArrayList#iterator}. */ + static final class ValueIterator extends AbstractIterator { + private final DoubleCursor cursor; + + private final double[] buffer; + private final int size; + + public ValueIterator(double[] buffer, int size) { + this.cursor = new DoubleCursor(); + this.cursor.index = -1; + this.size = size; + this.buffer = buffer; + } + + @Override + protected DoubleCursor fetch() { + if (cursor.index + 1 == size) return done(); + + cursor.value = buffer[++cursor.index]; + return cursor; + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new ValueIterator(buffer, size()); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + return forEach(procedure, 0, size()); + } + + /** + * Applies procedure to a slice of the list, fromIndex, inclusive, to + * toIndex, exclusive. + */ + public T forEach(T procedure, int fromIndex, final int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + final double[] buffer = this.buffer; + for (int i = fromIndex; i < toIndex; i++) { + procedure.apply(buffer[i]); + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(DoublePredicate predicate) { + final double[] buffer = this.buffer; + final int elementsCount = this.elementsCount; + int to = 0; + int from = 0; + try { + for (; from < elementsCount; from++) { + if (predicate.apply(buffer[from])) { + buffer[from] = 0d; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0d; + } + to++; + } + } finally { + // Keep the list in a consistent state, even if the predicate throws an exception. + for (; from < elementsCount; from++) { + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0d; + } + to++; + } + + this.elementsCount = to; + } + + return elementsCount - to; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + return forEach(predicate, 0, size()); + } + + /** + * Applies predicate to a slice of the list, fromIndex, inclusive, to + * toIndex, exclusive, or until predicate returns false. + */ + public T forEach(T predicate, int fromIndex, final int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + final double[] buffer = this.buffer; + for (int i = fromIndex; i < toIndex; i++) { + if (!predicate.apply(buffer[i])) break; + } + + return predicate; + } + + /** + * Create a list from a variable number of arguments or an array of double. The + * elements are copied from the argument to the internal buffer. + */ + public static DoubleArrayList from(double... elements) { + final DoubleArrayList list = new DoubleArrayList(elements.length); + list.add(elements); + return list; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/DoubleBufferVisualizer.java b/src/main/java/com/carrotsearch/hppc/DoubleBufferVisualizer.java new file mode 100755 index 00000000..f708c7a9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoubleBufferVisualizer.java @@ -0,0 +1,33 @@ +package com.carrotsearch.hppc; + +/** + * Reused buffer visualization routines. + * + * @see DoubleSet#visualizeKeyDistribution(int) + * @see DoubleVTypeMap#visualizeKeyDistribution(int) + */ +class DoubleBufferVisualizer { + static String visualizeKeyDistribution(double[] buffer, int max, int characters) { + final StringBuilder b = new StringBuilder(); + final char[] chars = ".123456789X".toCharArray(); + for (int i = 1, start = -1; i <= characters; i++) { + int end = (int) ((long) i * max / characters); + + if (start + 1 <= end) { + int taken = 0; + int slots = 0; + for (int slot = start + 1; slot <= end; slot++, slots++) { + if (!(Double.doubleToLongBits(buffer[slot]) == 0)) { + taken++; + } + } + b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]); + start = end; + } + } + while (b.length() < characters) { + b.append(' '); + } + return b.toString(); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/DoubleCollection.java b/src/main/java/com/carrotsearch/hppc/DoubleCollection.java new file mode 100755 index 00000000..e1c4f96a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoubleCollection.java @@ -0,0 +1,64 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.predicates.DoublePredicate; + +/** + * A collection allows basic, efficient operations on sets of elements (difference and + * intersection). + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java") +public interface DoubleCollection extends DoubleContainer { + /** + * Removes all occurrences of e from this collection. + * + * @param e Element to be removed from this collection, if present. + * @return The number of removed elements as a result of this call. + */ + public int removeAll(double e); + + /** + * Removes all elements in this collection that are present in c. + * + * @return Returns the number of removed elements. + */ + public int removeAll(DoubleLookupContainer c); + + /** + * Removes all elements in this collection for which the given predicate returns true + * . + * + * @return Returns the number of removed elements. + */ + public int removeAll(DoublePredicate predicate); + + /** + * Keeps all elements in this collection that are present in c. Runs in time + * proportional to the number of elements in this collection. Equivalent of sets intersection. + * + * @return Returns the number of removed elements. + */ + public int retainAll(DoubleLookupContainer c); + + /** + * Keeps all elements in this collection for which the given predicate returns true. + * + * @return Returns the number of removed elements. + */ + public int retainAll(DoublePredicate predicate); + + /** + * Removes all elements from this collection. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); +} diff --git a/src/main/java/com/carrotsearch/hppc/DoubleContainer.java b/src/main/java/com/carrotsearch/hppc/DoubleContainer.java new file mode 100755 index 00000000..b5719fd5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoubleContainer.java @@ -0,0 +1,76 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.DoubleCursor; +import com.carrotsearch.hppc.predicates.DoublePredicate; +import com.carrotsearch.hppc.procedures.DoubleProcedure; +import java.util.Iterator; + +/** A generic container holding doubles. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java") +public interface DoubleContainer extends Iterable { + /** + * Returns an iterator to a cursor traversing the collection. The order of traversal is not + * defined. More than one cursor may be active at a time. The behavior of iterators is undefined + * if structural changes are made to the underlying collection. + * + *

The iterator is implemented as a cursor and it returns the same cursor instance on + * every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current + * list's value (or index in the list) use the cursor's public fields. An example is shown below. + * + *

+   * for (DoubleCursor<double> c : container) {
+   *   System.out.println("index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator iterator(); + + /** + * Lookup a given element in the container. This operation has no speed guarantees (may be linear + * with respect to the size of this container). + * + * @return Returns true if this container has an element equal to e. + */ + public boolean contains(double e); + + /** + * Return the current number of elements in this container. The time for calculating the + * container's size may take O(n) time, although implementing classes should try to + * maintain the current size and return in constant time. + */ + public int size(); + + /** Shortcut for size() == 0. */ + public boolean isEmpty(); + + /** + * Copies all elements of this container to an array. + * + *

The returned array is always a copy, regardless of the storage used by the container. + */ + public double[] toArray(); + + /** + * Applies a procedure to all container elements. Returns the argument (any subclass + * of {@link DoubleProcedure}. This lets the caller to call methods of the argument by chaining + * the call (even if the argument is an anonymous type) to retrieve computed values, for example + * (IntContainer): + * + *

+   * int count = container.forEach(new IntProcedure() {
+   *   int count; // this is a field declaration in an anonymous class.
+   *
+   *   public void apply(int value) {
+   *     count++;
+   *   }
+   * }).count;
+   * 
+ */ + public T forEach(T procedure); + + /** + * Applies a predicate to container elements as long, as the predicate returns + * true. The iteration is interrupted otherwise. + */ + public T forEach(T predicate); +} diff --git a/src/main/java/com/carrotsearch/hppc/DoubleDeque.java b/src/main/java/com/carrotsearch/hppc/DoubleDeque.java new file mode 100755 index 00000000..423026ec --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoubleDeque.java @@ -0,0 +1,77 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.DoubleCursor; +import com.carrotsearch.hppc.predicates.DoublePredicate; +import com.carrotsearch.hppc.procedures.DoubleProcedure; +import java.util.Deque; +import java.util.Iterator; + +/** + * A linear collection that supports element insertion and removal at both ends. + * + * @see Deque + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java") +public interface DoubleDeque extends DoubleCollection { + /** + * Removes the first element that equals e. + * + * @return The deleted element's index or -1 if the element was not found. + */ + public int removeFirst(double e); + + /** + * Removes the last element that equals e. + * + * @return The deleted element's index or -1 if the element was not found. + */ + public int removeLast(double e); + + /** Inserts the specified element at the front of this deque. */ + public void addFirst(double e); + + /** Inserts the specified element at the end of this deque. */ + public void addLast(double e); + + /** + * Retrieves and removes the first element of this deque. + * + * @return the head (first) element of this deque. + */ + public double removeFirst(); + + /** + * Retrieves and removes the last element of this deque. + * + * @return the tail of this deque. + */ + public double removeLast(); + + /** + * Retrieves the first element of this deque but does not remove it. + * + * @return the head of this deque. + */ + public double getFirst(); + + /** + * Retrieves the last element of this deque but does not remove it. + * + * @return the head of this deque. + */ + public double getLast(); + + /** + * @return An iterator over elements in this deque in tail-to-head order. + */ + public Iterator descendingIterator(); + + /** Applies a procedure to all elements in tail-to-head order. */ + public T descendingForEach(T procedure); + + /** + * Applies a predicate to container elements as long, as the predicate returns + * true. The iteration is interrupted otherwise. + */ + public T descendingForEach(T predicate); +} diff --git a/src/main/java/com/carrotsearch/hppc/DoubleIndexedContainer.java b/src/main/java/com/carrotsearch/hppc/DoubleIndexedContainer.java new file mode 100755 index 00000000..faf6b27c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoubleIndexedContainer.java @@ -0,0 +1,93 @@ +package com.carrotsearch.hppc; + +import java.util.RandomAccess; +import java.util.stream.DoubleStream; + +/** + * An indexed container provides random access to elements based on an index. Indexes + * are zero-based. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeIndexedContainer.java") +public interface DoubleIndexedContainer extends DoubleCollection, RandomAccess { + /** + * Removes the first element that equals e1, returning whether an element has been + * removed. + */ + public boolean removeElement(double e1); + + /** + * Removes the first element that equals e1, returning its deleted position or + * -1 if the element was not found. + */ + public int removeFirst(double e1); + + /** + * Removes the last element that equals e1, returning its deleted position or + * -1 if the element was not found. + */ + public int removeLast(double e1); + + /** + * Returns the index of the first occurrence of the specified element in this list, or -1 if this + * list does not contain the element. + */ + public int indexOf(double e1); + + /** + * Returns the index of the last occurrence of the specified element in this list, or -1 if this + * list does not contain the element. + */ + public int lastIndexOf(double e1); + + /** Adds an element to the end of this container (the last index is incremented by one). */ + public void add(double e1); + + /** + * Inserts the specified element at the specified position in this list. + * + * @param index The index at which the element should be inserted, shifting any existing and + * subsequent elements to the right. + */ + public void insert(int index, double e1); + + /** + * Replaces the element at the specified position in this list with the specified element. + * + * @return Returns the previous value in the list. + */ + public double set(int index, double e1); + + /** + * @return Returns the element at index index from the list. + */ + public double get(int index); + + /** + * Removes the element at the specified position in this container and returns it. + * + * @see #removeFirst + * @see #removeLast + * @see #removeAll + */ + public double removeAt(int index); + + /** Removes and returns the last element of this container. This container must not be empty. */ + public double removeLast(); + + /** + * Removes from this container all of the elements with indexes between fromIndex, + * inclusive, and toIndex, exclusive. + */ + public void removeRange(int fromIndex, int toIndex); + + /** Returns this container elements as a stream. */ + public DoubleStream stream(); + + /** Sorts the elements in this container and returns this container. */ + public DoubleIndexedContainer sort(); + + /** Reverses the elements in this container and returns this container. */ + public DoubleIndexedContainer reverse(); +} diff --git a/src/main/java/com/carrotsearch/hppc/DoubleLookupContainer.java b/src/main/java/com/carrotsearch/hppc/DoubleLookupContainer.java new file mode 100755 index 00000000..c27e6b4b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoubleLookupContainer.java @@ -0,0 +1,12 @@ +package com.carrotsearch.hppc; + +/** + * Marker interface for containers that can check if they contain a given object in at least time + * O(log n) and ideally in amortized constant time O(1). + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeLookupContainer.java") +public interface DoubleLookupContainer extends DoubleContainer { + public boolean contains(double e); +} diff --git a/src/main/java/com/carrotsearch/hppc/DoublePgmIndex.java b/src/main/java/com/carrotsearch/hppc/DoublePgmIndex.java new file mode 100755 index 00000000..ee5ac213 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoublePgmIndex.java @@ -0,0 +1,600 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.DoubleCursor; +import com.carrotsearch.hppc.procedures.DoubleProcedure; +import java.util.Arrays; +import java.util.Iterator; + +/** + * Space-efficient index that enables fast rank/range search operations on a sorted sequence of + * double. + * + *

Implementation of the PGM-Index described at https://pgm.di.unipi.it/, based on the paper + * + *

+ *   Paolo Ferragina and Giorgio Vinciguerra.
+ *   The PGM-index: a fully-dynamic compressed learned index with provable worst-case bounds.
+ *   PVLDB, 13(8): 1162-1175, 2020.
+ * 
+ * + * It provides {@code rank} and {@code range} search operations. {@code indexOf()} is faster than + * B+Tree, and the index is much more compact. {@code contains()} is between 4x to 7x slower than + * {@code IntHashSet#contains()}, but between 2.5x to 3x faster than {@link Arrays#binarySearch}. + * + *

Its compactness (40KB for 200MB of keys) makes it efficient for very large collections, the + * index fitting easily in the L2 cache. The {@code epsilon} parameter should be set according to + * the desired space-time trade-off. A smaller value makes the estimation more precise and the range + * smaller but at the cost of increased space usage. In practice, {@code epsilon} 64 is a good sweet + * spot. + * + *

Internally the index uses an optimal piecewise linear mapping from keys to their position in + * the sorted order. This mapping is represented as a sequence of linear models (segments) which are + * themselves recursively indexed by other piecewise linear mappings. + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypePgmIndex.java") +public class DoublePgmIndex implements Accountable { + + /** Empty immutable DoublePgmIndex. */ + public static final DoublePgmIndex EMPTY = new DoubleEmptyPgmIndex(); + + /** + * Epsilon approximation range when searching the list of keys. Controls the size of the returned + * search range, strictly greater than 0. It should be set according to the desired space-time + * trade-off. A smaller value makes the estimation more precise and the range smaller but at the + * cost of increased space usage. + * + *

With EPSILON=64 the benchmark with 200MB of keys shows that this PGM index requires only 2% + * additional memory on average (40KB). It depends on the distribution of the keys. This epsilon + * value is good even for 2MB of keys. With EPSILON=32: +5% speed, but 4x space (160KB). + */ + public static final int EPSILON = 64; + + /** + * Epsilon approximation range for the segments layers. Controls the size of the search range in + * the hierarchical segment lists, strictly greater than 0. + */ + public static final int EPSILON_RECURSIVE = 32; + + /** Size of a key, measured in {@link Integer#BYTES} because the key is stored in an int[]. */ + public static final int KEY_SIZE = + RamUsageEstimator.primitiveSizes.get(double.class) / Integer.BYTES; + + /** 2x {@link #KEY_SIZE}. */ + public static final int DOUBLE_KEY_SIZE = KEY_SIZE * 2; + + /** + * Data size of a segment, measured in {@link Integer#BYTES}, because segments are stored in an + * int[]. + */ + public static final int SEGMENT_DATA_SIZE = KEY_SIZE * 3; + + /** Initial value of the exponential jump when scanning out of the epsilon range. */ + public static final int BEYOND_EPSILON_JUMP = 16; + + /** + * The list of keys for which this index is built. It is sorted and may contain duplicate + * elements. + */ + public final DoubleArrayList keys; + + /** The size of the key set. That is, the number of distinct elements in {@link #keys}. */ + public final int size; + + /** The lowest key in {@link #keys}. */ + public final double firstKey; + + /** The highest key in {@link #keys}. */ + public final double lastKey; + + /** The epsilon range used to build this index. */ + public final int epsilon; + + /** The recursive epsilon range used to build this index. */ + public final int epsilonRecursive; + + /** The offsets in {@link #segmentData} of the first segment of each segment level. */ + public final int[] levelOffsets; + + /** The index data. It contains all the segments for all the levels. */ + public final int[] segmentData; + + private DoublePgmIndex( + DoubleArrayList keys, + int size, + int epsilon, + int epsilonRecursive, + int[] levelOffsets, + int[] segmentData) { + assert keys.size() > 0; + assert size > 0 && size <= keys.size(); + assert epsilon > 0; + assert epsilonRecursive > 0; + this.keys = keys; + this.size = size; + firstKey = keys.get(0); + lastKey = keys.get(keys.size() - 1); + this.epsilon = epsilon; + this.epsilonRecursive = epsilonRecursive; + this.levelOffsets = levelOffsets; + this.segmentData = segmentData; + } + + /** Empty set constructor. */ + private DoublePgmIndex() { + keys = new DoubleArrayList(0); + size = 0; + firstKey = 0d; + lastKey = 0d; + epsilon = 0; + epsilonRecursive = 0; + levelOffsets = new int[0]; + segmentData = levelOffsets; + } + + /** Returns the size of the key set. That is, the number of distinct elements in {@link #keys}. */ + public int size() { + return size; + } + + /** Returns whether this key set is empty. */ + public boolean isEmpty() { + return size() == 0; + } + + /** Returns whether this key set contains the given key. */ + public boolean contains(double key) { + return indexOf(key) >= 0; + } + + /** + * Searches the specified key, and returns its index in the element list. If multiple elements are + * equal to the specified key, there is no guarantee which one will be found. + * + * @return The index of the searched key if it is present; otherwise, {@code (-(insertion + * point) - 1)}. The insertion point is defined as the point at which the key would + * be inserted into the list: the index of the first element greater than the key, or {@link + * #keys}#{@code size()} if all the elements are less than the specified key. Note that this + * guarantees that the return value will be >= 0 if and only if the key is found. + */ + public int indexOf(double key) { + if (key < firstKey) { + return -1; + } + if (key > lastKey) { + return -keys.size() - 1; + } + final int[] segmentData = this.segmentData; + int segmentDataIndex = findSegment(key); + int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData); + int index = + Math.min( + approximateIndex(key, segmentDataIndex, segmentData), + Math.min(nextIntercept, keys.size() - 1)); + assert index >= 0 && index < keys.size(); + double k = keys.get(index); + if (key < k) { + // Scan sequentially before the approximated index, within epsilon range. + final int fromIndex = Math.max(index - epsilon - 1, 0); + while (--index >= fromIndex) { + k = keys.get(index); + if (key > k) { + return -index - 2; + } + if ((Double.doubleToLongBits(key) == Double.doubleToLongBits(k))) { + return index; + } + } + // Continue scanning out of the epsilon range. + // This might happen in rare cases of precision error during the approximation + // computation for longs (we don't have long double 128 bits in Java). + // This might also happen in rare corner cases of large duplicate elements + // sequence at the epsilon range boundary. + index++; + int jump = BEYOND_EPSILON_JUMP; + do { + int loIndex = Math.max(index - jump, 0); + if (key >= keys.get(loIndex)) { + return Arrays.binarySearch(keys.buffer, loIndex, index, key); + } + index = loIndex; + jump <<= 1; + } while (index > 0); + return -1; + } else if ((Double.doubleToLongBits(key) == Double.doubleToLongBits(k))) { + return index; + } else { + // Scan sequentially after the approximated index, within epsilon range. + final int toIndex = Math.min(index + epsilon + 3, keys.size()); + while (++index < toIndex) { + k = keys.get(index); + if (key < k) { + return -index - 1; + } + if ((Double.doubleToLongBits(key) == Double.doubleToLongBits(k))) { + return index; + } + } + // Continue scanning out of the epsilon range. + int jump = BEYOND_EPSILON_JUMP; + do { + int hiIndex = Math.min(index + jump, keys.size()); + if (key <= keys.get(hiIndex)) { + return Arrays.binarySearch(keys.buffer, index, hiIndex, key); + } + index = hiIndex; + jump <<= 1; + } while (index < keys.size()); + return -keys.size() - 1; + } + } + + /** + * Returns, for any value {@code x}, the number of keys in the sorted list which are smaller than + * {@code x}. It is equal to {@link #indexOf} if {@code x} belongs to the list, or -{@link + * #indexOf}-1 otherwise. + * + *

If multiple elements are equal to the specified key, there is no guarantee which one will be + * found. + * + * @return The index of the searched key if it is present; otherwise, the {@code insertion point}. + * The insertion point is defined as the point at which the key would be inserted into + * the list: the index of the first element greater than the key, or {@link #keys}#{@code + * size()} if all the elements are less than the specified key. Note that this method always + * returns a value >= 0. + */ + public int rank(double x) { + int index = indexOf(x); + return index >= 0 ? index : -index - 1; + } + + /** + * Returns the number of keys in the list that are greater than or equal to {@code minKey} + * (inclusive), and less than or equal to {@code maxKey} (inclusive). + */ + public int rangeCardinality(double minKey, double maxKey) { + int fromIndex = rank(minKey); + int maxIndex = indexOf(maxKey); + int toIndex = maxIndex >= 0 ? maxIndex + 1 : -maxIndex - 1; + return Math.max(toIndex - fromIndex, 0); + } + + /** + * Returns an iterator over the keys in the list that are greater than or equal to {@code minKey} + * (inclusive), and less than or equal to {@code maxKey} (inclusive). + */ + public Iterator rangeIterator(double minKey, double maxKey) { + int fromIndex = rank(minKey); + return new RangeIterator(keys, fromIndex, maxKey); + } + + /** + * Applies {@code procedure} to the keys in the list that are greater than or equal to {@code + * minKey} (inclusive), and less than or equal to {@code maxKey} (inclusive). + */ + public T forEachInRange(T procedure, double minKey, double maxKey) { + final double[] buffer = keys.buffer; + double k; + for (int i = rank(minKey), size = keys.size(); i < size && (k = buffer[i]) <= maxKey; i++) { + procedure.apply(k); + } + return procedure; + } + + /** + * Estimates the allocated memory. It does not count the memory for the list of keys, only for the + * index itself. + */ + @Override + public long ramBytesAllocated() { + // int: size, epsilon, epsilonRecursive + // double: firstKey, lastKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 3 * Integer.BYTES + + 2L * KEY_SIZE * Integer.BYTES + // + keys.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(levelOffsets) + + RamUsageEstimator.shallowSizeOfArray(segmentData); + } + + /** + * Estimates the bytes that are actually used. It does not count the memory for the list of keys, + * only for the index itself. + */ + @Override + public long ramBytesUsed() { + // int: size, epsilon, epsilonRecursive + // double: firstKey, lastKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 3 * Integer.BYTES + + 2L * KEY_SIZE * Integer.BYTES + // + keys.ramBytesUsed() + + RamUsageEstimator.shallowSizeOfArray(levelOffsets) + + RamUsageEstimator.shallowSizeOfArray(segmentData); + } + + /** + * Finds the segment responsible for a given key, that is, the rightmost segment having its first + * key <= the searched key. + * + * @return the segment data index; or -1 if none. + */ + private int findSegment(double key) { + assert key >= firstKey && key <= lastKey; + final int epsilonRecursive = this.epsilonRecursive; + final int[] levelOffsets = this.levelOffsets; + final int[] segmentData = this.segmentData; + int level = levelOffsets.length - 1; + int segmentDataIndex = levelOffsets[level] * SEGMENT_DATA_SIZE; + while (--level >= 0) { + int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData); + int index = Math.min(approximateIndex(key, segmentDataIndex, segmentData), nextIntercept); + assert index >= 0 && index <= levelOffsets[level + 1] - levelOffsets[level] - 1; + int sdIndex = (levelOffsets[level] + index) * SEGMENT_DATA_SIZE; + if (getKey(sdIndex, segmentData) <= key) { + // Scan sequentially segments after the approximated index, within the epsilon range. + final int levelNumSegments = levelOffsets[level + 1] - levelOffsets[level] - 1; + final int toIndex = Math.min(index + epsilonRecursive + 3, levelNumSegments); + while (index++ < toIndex && getKey(sdIndex + SEGMENT_DATA_SIZE, segmentData) <= key) { + sdIndex += SEGMENT_DATA_SIZE; + } + } else { + // Scan sequentially segments before the approximated index, within the epsilon range. + final int fromIndex = Math.max(index - epsilonRecursive - 1, 0); + while (index-- > fromIndex) { + sdIndex -= SEGMENT_DATA_SIZE; + if (getKey(sdIndex, segmentData) <= key) { + break; + } + } + } + segmentDataIndex = sdIndex; + } + assert segmentDataIndex >= 0; + return segmentDataIndex; + } + + private int approximateIndex(double key, int segmentDataIndex, int[] segmentData) { + long intercept = getIntercept(segmentDataIndex, segmentData); + double sKey = getKey(segmentDataIndex, segmentData); + double slope = getSlope(segmentDataIndex, segmentData); + int index = (int) (slope * ((double) key - sKey) + intercept); + return Math.max(index, 0); + } + + private static long getIntercept(int segmentDataIndex, int[] segmentData) { + return PgmIndexUtil.getIntercept(segmentDataIndex, segmentData, KEY_SIZE); + } + + private double getKey(int segmentDataIndex, int[] segmentData) { + return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0d); + } + + private static double getSlope(int segmentDataIndex, int[] segmentData) { + return PgmIndexUtil.getSlope(segmentDataIndex + DOUBLE_KEY_SIZE, segmentData, KEY_SIZE); + } + + /** Empty immutable PGM Index. */ + private static class DoubleEmptyPgmIndex extends DoublePgmIndex { + + private final Iterator emptyIterator = new DoubleEmptyIterator(); + + @Override + public int indexOf(double key) { + return -1; + } + + @Override + public Iterator rangeIterator(double minKey, double maxKey) { + return emptyIterator; + } + + @Override + public T forEachInRange(T procedure, double minKey, double maxKey) { + return procedure; + } + + private static class DoubleEmptyIterator extends AbstractIterator { + @Override + protected DoubleCursor fetch() { + return done(); + } + } + } + + /** Iterator over a range of elements in a sorted array. */ + protected static class RangeIterator extends AbstractIterator { + private final double[] buffer; + private final int size; + private final DoubleCursor cursor; + private final double maxKey; + + /** Range iterator from {@code fromIndex} (inclusive) to {@code maxKey} (inclusive). */ + protected RangeIterator(DoubleArrayList keys, int fromIndex, double maxKey) { + this.buffer = keys.buffer; + this.size = keys.size(); + this.cursor = new DoubleCursor(); + this.cursor.index = fromIndex; + this.maxKey = maxKey; + } + + @Override + protected DoubleCursor fetch() { + if (cursor.index >= size) { + return done(); + } + cursor.value = buffer[cursor.index++]; + if (cursor.value > maxKey) { + cursor.index = size; + return done(); + } + return cursor; + } + } + + /** Builds a {@link DoublePgmIndex} on a provided sorted list of keys. */ + public static class DoubleBuilder implements PlaModel.SegmentConsumer, Accountable { + + protected DoubleArrayList keys; + protected int epsilon = EPSILON; + protected int epsilonRecursive = EPSILON_RECURSIVE; + protected PlaModel plam; + protected int size; + protected IntArrayList segmentData; + protected int numSegments; + + /** Sets the sorted list of keys to build the index for; duplicate elements are allowed. */ + public DoubleBuilder setSortedKeys(DoubleArrayList keys) { + this.keys = keys; + return this; + } + + /** Sets the sorted array of keys to build the index for; duplicate elements are allowed. */ + public DoubleBuilder setSortedKeys(double[] keys, int length) { + DoubleArrayList keyList = new DoubleArrayList(0); + keyList.buffer = keys; + keyList.elementsCount = length; + return setSortedKeys(keyList); + } + + /** Sets the epsilon range to use when learning the segments for the list of keys. */ + public DoubleBuilder setEpsilon(int epsilon) { + if (epsilon <= 0) { + throw new IllegalArgumentException("epsilon must be > 0"); + } + this.epsilon = epsilon; + return this; + } + + /** + * Sets the recursive epsilon range to use when learning the segments for the segment levels. + */ + public DoubleBuilder setEpsilonRecursive(int epsilonRecursive) { + if (epsilonRecursive <= 0) { + throw new IllegalArgumentException("epsilonRecursive must be > 0"); + } + this.epsilonRecursive = epsilonRecursive; + return this; + } + + /** Builds the {@link DoublePgmIndex}; or {@link #EMPTY} if there are no keys in the list. */ + public DoublePgmIndex build() { + if (keys == null || keys.size() == 0) { + return (DoublePgmIndex) EMPTY; + } + plam = new PlaModel(epsilon); + + int segmentsInitialCapacity = + Math.min( + Math.max(keys.size() / (2 * epsilon * epsilon) * SEGMENT_DATA_SIZE, 16), 1 << 19); + segmentData = new IntArrayList(segmentsInitialCapacity); + IntArrayList levelOffsets = new IntArrayList(16); + + int levelOffset = 0; + levelOffsets.add(levelOffset); + int levelNumSegments = buildFirstLevel(); + while (levelNumSegments > 1) { + int nextLevelOffset = numSegments; + levelOffsets.add(nextLevelOffset); + levelNumSegments = buildUpperLevel(levelOffset, levelNumSegments); + levelOffset = nextLevelOffset; + } + + int[] segmentDataFinal = segmentData.toArray(); + int[] levelOffsetsFinal = levelOffsets.toArray(); + return new DoublePgmIndex( + keys, size, epsilon, epsilonRecursive, levelOffsetsFinal, segmentDataFinal); + } + + private int buildFirstLevel() { + assert numSegments == 0; + int numKeys = keys.size(); + int size = 0; + double key = keys.get(0); + size++; + plam.addKey(key, 0, this); + for (int i = 1; i < numKeys; i++) { + double nextKey = keys.get(i); + if (!(Double.doubleToLongBits(nextKey) == Double.doubleToLongBits(key))) { + key = nextKey; + plam.addKey(key, i, this); + size++; + } + } + plam.finish(this); + addSentinelSegment(numKeys); + this.size = size; + return numSegments - 1; + } + + private int buildUpperLevel(int levelOffset, int levelNumSegments) { + plam.setEpsilon(epsilonRecursive); + assert numSegments > 0; + int initialNumSegments = numSegments; + int segmentDataIndex = levelOffset * SEGMENT_DATA_SIZE; + double key = getKey(segmentDataIndex, segmentData.buffer); + plam.addKey(key, 0, this); + for (int i = 1; i < levelNumSegments; i++) { + segmentDataIndex += SEGMENT_DATA_SIZE; + double nextKey = getKey(segmentDataIndex, segmentData.buffer); + if (!(Double.doubleToLongBits(nextKey) == Double.doubleToLongBits(key))) { + key = nextKey; + plam.addKey(key, i, this); + } + } + plam.finish(this); + addSentinelSegment(levelNumSegments); + return numSegments - initialNumSegments - 1; + } + + private double getKey(int segmentDataIndex, int[] segmentData) { + return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0d); + } + + /** + * Adds a sentinel segment that is used to give a limit for the position approximation, but does + * not count in the number of segments per level. + */ + private void addSentinelSegment(int endIndex) { + // This sentinel segment is used in findSegment(). + accept(Double.MAX_VALUE, 0d, endIndex); + } + + @Override + public void accept(double firstKey, double slope, long intercept) { + PgmIndexUtil.addIntercept(intercept, segmentData, KEY_SIZE); + PgmIndexUtil.addKey((double) firstKey, segmentData); + PgmIndexUtil.addSlope(slope, segmentData, KEY_SIZE); + numSegments++; + assert segmentData.size() == numSegments * SEGMENT_DATA_SIZE; + } + + /** + * Estimates the allocated memory. It does not count the memory for the list of keys, only for + * the builder itself. + */ + @Override + public long ramBytesAllocated() { + // int: epsilon, epsilonRecursive, size, numSegments + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + // + keys.ramBytesAllocated() + + plam.ramBytesAllocated() + + segmentData.ramBytesAllocated(); + } + + /** + * Estimates the bytes that are actually used. It does not count the memory for the list of + * keys, only for the builder itself. + */ + @Override + public long ramBytesUsed() { + // int: epsilon, epsilonRecursive, size, numSegments + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + // + keys.ramBytesUsed() + + plam.ramBytesUsed() + + segmentData.ramBytesUsed(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/DoubleStack.java b/src/main/java/com/carrotsearch/hppc/DoubleStack.java new file mode 100755 index 00000000..bf0a2219 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoubleStack.java @@ -0,0 +1,137 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.DoubleCursor; + +/** + * A subclass of {@link DoubleArrayList} adding stack-related utility methods. The top of the stack + * is at the {@link #size()} - 1 element. + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java") +public class DoubleStack extends DoubleArrayList { + /** New instance with sane defaults. */ + public DoubleStack() { + super(); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public DoubleStack(int expectedElements) { + super(expectedElements); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public DoubleStack(int expectedElements, ArraySizingStrategy resizer) { + super(expectedElements, resizer); + } + + /** Create a stack by pushing all elements of another container to it. */ + public DoubleStack(DoubleContainer container) { + super(container); + } + + /** Adds one double to the stack. */ + public void push(double e1) { + ensureBufferSpace(1); + buffer[elementsCount++] = e1; + } + + /** Adds two doubles to the stack. */ + public void push(double e1, double e2) { + ensureBufferSpace(2); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + } + + /** Adds three doubles to the stack. */ + public void push(double e1, double e2, double e3) { + ensureBufferSpace(3); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + buffer[elementsCount++] = e3; + } + + /** Adds four doubles to the stack. */ + public void push(double e1, double e2, double e3, double e4) { + ensureBufferSpace(4); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + buffer[elementsCount++] = e3; + buffer[elementsCount++] = e4; + } + + /** Add a range of array elements to the stack. */ + public void push(double[] elements, int start, int len) { + assert start >= 0 && len >= 0; + + ensureBufferSpace(len); + System.arraycopy(elements, start, buffer, elementsCount, len); + elementsCount += len; + } + + /** + * Vararg-signature method for pushing elements at the top of the stack. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + */ + public final void push(double... elements) { + push(elements, 0, elements.length); + } + + /** Pushes all elements from another container to the top of the stack. */ + public int pushAll(DoubleContainer container) { + return addAll(container); + } + + /** Pushes all elements from another iterable to the top of the stack. */ + public int pushAll(Iterable iterable) { + return addAll(iterable); + } + + /** Discard an arbitrary number of elements from the top of the stack. */ + public void discard(int count) { + assert elementsCount >= count; + + elementsCount -= count; + } + + /** Discard the top element from the stack. */ + public void discard() { + assert elementsCount > 0; + + elementsCount--; + } + + /** Remove the top element from the stack and return it. */ + public double pop() { + return removeLast(); + } + + /** Peek at the top element on the stack. */ + public double peek() { + assert elementsCount > 0; + return buffer[elementsCount - 1]; + } + + /** Create a stack by pushing a variable number of arguments to it. */ + public static DoubleStack from(double... elements) { + final DoubleStack stack = new DoubleStack(elements.length); + stack.push(elements); + return stack; + } + + /** {@inheritDoc} */ + @Override + public DoubleStack clone() { + return (DoubleStack) super.clone(); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/FloatArrayDeque.java b/src/main/java/com/carrotsearch/hppc/FloatArrayDeque.java new file mode 100755 index 00000000..e3d29082 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatArrayDeque.java @@ -0,0 +1,776 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; + +import com.carrotsearch.hppc.cursors.FloatCursor; +import com.carrotsearch.hppc.predicates.FloatPredicate; +import com.carrotsearch.hppc.procedures.FloatProcedure; +import java.util.*; + +/** An array-backed {@link FloatDeque}. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java") +public class FloatArrayDeque extends AbstractFloatCollection + implements FloatDeque, Preallocable, Cloneable, Accountable { + + /** Reuse the same strategy instance. */ + private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = + BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; + + /** Internal array for storing elements of the deque. */ + public float[] buffer = FloatArrayList.EMPTY_ARRAY; + + /** + * The index of the element at the head of the deque or an arbitrary number equal to tail if the + * deque is empty. + */ + public int head; + + /** The index at which the next element would be added to the tail of the deque. */ + public int tail; + + /** Buffer resizing strategy. */ + protected final ArraySizingStrategy resizer; + + /** New instance with sane defaults. */ + public FloatArrayDeque() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public FloatArrayDeque(int expectedElements) { + this(expectedElements, DEFAULT_SIZING_STRATEGY); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public FloatArrayDeque(int expectedElements, ArraySizingStrategy resizer) { + assert resizer != null; + this.resizer = resizer; + ensureCapacity(expectedElements); + } + + /** + * Creates a new deque from elements of another container, appending elements at the end of the + * deque in the iteration order. + */ + public FloatArrayDeque(FloatContainer container) { + this(container.size()); + addLast(container); + } + + /** {@inheritDoc} */ + @Override + public void addFirst(float e1) { + int h = oneLeft(head, buffer.length); + if (h == tail) { + ensureBufferSpace(1); + h = oneLeft(head, buffer.length); + } + buffer[head = h] = e1; + } + + /** + * Vararg-signature method for adding elements at the front of this deque. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + * + * @param elements The elements to add. + */ + public final void addFirst(float... elements) { + ensureBufferSpace(elements.length); + for (float k : elements) { + addFirst(k); + } + } + + /** + * Inserts all elements from the given container to the front of this deque. + * + * @param container The container to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addFirst(FloatContainer container) { + int size = container.size(); + ensureBufferSpace(size); + + for (FloatCursor cursor : container) { + addFirst(cursor.value); + } + + return size; + } + + /** + * Inserts all elements from the given iterable to the front of this deque. + * + * @param iterable The iterable to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addFirst(Iterable iterable) { + int size = 0; + for (FloatCursor cursor : iterable) { + addFirst(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public void addLast(float e1) { + int t = oneRight(tail, buffer.length); + if (head == t) { + ensureBufferSpace(1); + t = oneRight(tail, buffer.length); + } + buffer[tail] = e1; + tail = t; + } + + /** + * Vararg-signature method for adding elements at the end of this deque. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + * + * @param elements The elements to iterate over. + */ + public final void addLast(float... elements) { + ensureBufferSpace(1); + for (float k : elements) { + addLast(k); + } + } + + /** + * Inserts all elements from the given container to the end of this deque. + * + * @param container The container to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addLast(FloatContainer container) { + int size = container.size(); + ensureBufferSpace(size); + + for (FloatCursor cursor : container) { + addLast(cursor.value); + } + + return size; + } + + /** + * Inserts all elements from the given iterable to the end of this deque. + * + * @param iterable The iterable to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addLast(Iterable iterable) { + int size = 0; + for (FloatCursor cursor : iterable) { + addLast(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public float removeFirst() { + assert size() > 0 : "The deque is empty."; + + final float result = buffer[head]; + buffer[head] = 0f; + head = oneRight(head, buffer.length); + return result; + } + + /** {@inheritDoc} */ + @Override + public float removeLast() { + assert size() > 0 : "The deque is empty."; + + tail = oneLeft(tail, buffer.length); + final float result = buffer[tail]; + buffer[tail] = 0f; + return result; + } + + /** {@inheritDoc} */ + @Override + public float getFirst() { + assert size() > 0 : "The deque is empty."; + + return buffer[head]; + } + + /** {@inheritDoc} */ + @Override + public float getLast() { + assert size() > 0 : "The deque is empty."; + + return buffer[oneLeft(tail, buffer.length)]; + } + + /** {@inheritDoc} */ + @Override + public int removeFirst(float e1) { + final int index = bufferIndexOf(e1); + if (index >= 0) removeAtBufferIndex(index); + return index; + } + + /** + * Return the index of the first (counting from head) element equal to e1. The index + * points to the {@link #buffer} array. + * + * @param e1 The element to look for. + * @return Returns the index of the first element equal to e1 or -1 if + * not found. + */ + public int bufferIndexOf(float e1) { + final int last = tail; + final int bufLen = buffer.length; + for (int i = head; i != last; i = oneRight(i, bufLen)) { + if ((Float.floatToIntBits(e1) == Float.floatToIntBits(buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int removeLast(float e1) { + final int index = lastBufferIndexOf(e1); + if (index >= 0) { + removeAtBufferIndex(index); + } + return index; + } + + /** + * Return the index of the last (counting from tail) element equal to e1. The index + * points to the {@link #buffer} array. + * + * @param e1 The element to look for. + * @return Returns the index of the first element equal to e1 or -1 if + * not found. + */ + public int lastBufferIndexOf(float e1) { + final int bufLen = buffer.length; + final int last = oneLeft(head, bufLen); + for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) { + if ((Float.floatToIntBits(e1) == Float.floatToIntBits(buffer[i]))) return i; + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(float e1) { + int removed = 0; + final int last = tail; + final int bufLen = buffer.length; + int from, to; + for (from = to = head; from != last; from = oneRight(from, bufLen)) { + if ((Float.floatToIntBits(e1) == Float.floatToIntBits(buffer[from]))) { + buffer[from] = 0f; + removed++; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0f; + } + + to = oneRight(to, bufLen); + } + + tail = to; + return removed; + } + + /** + * Removes the element at index in the internal {#link {@link #buffer} array, + * returning its value. + * + * @param index Index of the element to remove. The index must be located between {@link #head} + * and {@link #tail} in modulo {@link #buffer} arithmetic. + */ + public void removeAtBufferIndex(int index) { + assert (head <= tail ? index >= head && index < tail : index >= head || index < tail) + : "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ")."; + + // Cache fields in locals (hopefully moved to registers). + final float[] buffer = this.buffer; + final int bufLen = buffer.length; + final int lastIndex = bufLen - 1; + final int head = this.head; + final int tail = this.tail; + + final int leftChunk = Math.abs(index - head) % bufLen; + final int rightChunk = Math.abs(tail - index) % bufLen; + + if (leftChunk < rightChunk) { + if (index >= head) { + System.arraycopy(buffer, head, buffer, head + 1, leftChunk); + } else { + System.arraycopy(buffer, 0, buffer, 1, index); + buffer[0] = buffer[lastIndex]; + System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head); + } + buffer[head] = 0f; + this.head = oneRight(head, bufLen); + } else { + if (index < tail) { + System.arraycopy(buffer, index + 1, buffer, index, rightChunk); + } else { + System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index); + buffer[lastIndex] = buffer[0]; + System.arraycopy(buffer, 1, buffer, 0, tail); + } + buffer[tail] = 0f; + this.tail = oneLeft(tail, bufLen); + } + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int size() { + if (head <= tail) return tail - head; + else return (tail - head + buffer.length); + } + + /** + * {@inheritDoc} + * + *

The internal array buffers are not released as a result of this call. + * + * @see #release() + */ + @Override + public void clear() { + if (head < tail) { + Arrays.fill(buffer, head, tail, 0f); + } else { + Arrays.fill(buffer, 0, tail, 0f); + Arrays.fill(buffer, head, buffer.length, 0f); + } + this.head = tail = 0; + } + + /** Release internal buffers of this deque and reallocate with the default buffer. */ + public void release() { + this.head = tail = 0; + buffer = FloatArrayList.EMPTY_ARRAY; + ensureBufferSpace(0); + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + ensureBufferSpace(expectedElements - size()); + } + + /** + * Ensures the internal buffer has enough free slots to store expectedAdditions. + * Increases internal buffer size if needed. + */ + protected void ensureBufferSpace(int expectedAdditions) { + final int bufferLen = buffer.length; + final int elementsCount = size(); + + if (elementsCount + expectedAdditions >= bufferLen) { + final int emptySlot = 1; // deque invariant: always an empty slot. + final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions); + assert newSize >= (elementsCount + expectedAdditions + emptySlot) + : "Resizer failed to" + + " return sensible new size: " + + newSize + + " <= " + + (elementsCount + expectedAdditions); + + try { + final float[] newBuffer = (new float[newSize]); + if (bufferLen > 0) { + toArray(newBuffer); + tail = elementsCount; + head = 0; + } + this.buffer = newBuffer; + } catch (OutOfMemoryError e) { + throw new BufferAllocationException( + "Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize); + } + } + } + + /** {@inheritDoc} */ + @Override + public float[] toArray() { + + final int size = size(); + return toArray((new float[size])); + } + + /** + * Copies elements of this deque to an array. The content of the target array is + * filled from index 0 (head of the queue) to index size() - 1 (tail of the queue). + * + * @param target The target array must be large enough to hold all elements. + * @return Returns the target argument for chaining. + */ + public float[] toArray(float[] target) { + assert target.length >= size() : "Target array must be >= " + size(); + + if (head < tail) { + // The contents is not wrapped around. Just copy. + System.arraycopy(buffer, head, target, 0, size()); + } else if (head > tail) { + // The contents is split. Merge elements from the following indexes: + // [head...buffer.length - 1][0, tail - 1] + final int rightCount = buffer.length - head; + System.arraycopy(buffer, head, target, 0, rightCount); + System.arraycopy(buffer, 0, target, rightCount, tail); + } + + return target; + } + + /** + * Clone this object. The returned clone will reuse the same hash function and array resizing + * strategy. + */ + @Override + public FloatArrayDeque clone() { + try { + + FloatArrayDeque cloned = (FloatArrayDeque) super.clone(); + cloned.buffer = buffer.clone(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Move one index to the left, wrapping around buffer. */ + protected static int oneLeft(int index, int modulus) { + if (index >= 1) { + return index - 1; + } + return modulus - 1; + } + + /** Move one index to the right, wrapping around buffer. */ + protected static int oneRight(int index, int modulus) { + if (index + 1 == modulus) { + return 0; + } + return index + 1; + } + + @Override + public long ramBytesAllocated() { + // int: head, tail + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES * 2 + + resizer.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(buffer); + } + + @Override + public long ramBytesUsed() { + // int: head, tail + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES * 2 + + resizer.ramBytesUsed() + + RamUsageEstimator.shallowUsedSizeOfArray(buffer, size()); + } + + /** An iterator implementation for {@link ObjectArrayDeque#iterator}. */ + private final class ValueIterator extends AbstractIterator { + private final FloatCursor cursor; + private int remaining; + + public ValueIterator() { + cursor = new FloatCursor(); + cursor.index = oneLeft(head, buffer.length); + this.remaining = size(); + } + + @Override + protected FloatCursor fetch() { + if (remaining == 0) { + return done(); + } + + remaining--; + cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)]; + return cursor; + } + } + + /** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */ + private final class DescendingValueIterator extends AbstractIterator { + private final FloatCursor cursor; + private int remaining; + + public DescendingValueIterator() { + cursor = new FloatCursor(); + cursor.index = tail; + this.remaining = size(); + } + + @Override + protected FloatCursor fetch() { + if (remaining == 0) return done(); + + remaining--; + cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)]; + return cursor; + } + } + + /** + * Returns a cursor over the values of this deque (in head to tail order). The iterator is + * implemented as a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in + * the deque's buffer) use the cursor's public fields. An example is shown below. + * + *

+   * for (IntValueCursor c : intDeque) {
+   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator iterator() { + return new ValueIterator(); + } + + /** + * Returns a cursor over the values of this deque (in tail to head order). The iterator is + * implemented as a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in + * the deque's buffer) use the cursor's public fields. An example is shown below. + * + *
+   * for (Iterator<IntCursor> i = intDeque.descendingIterator(); i.hasNext();) {
+   *   final IntCursor c = i.next();
+   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator descendingIterator() { + return new DescendingValueIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + forEach(procedure, head, tail); + return procedure; + } + + /** + * Applies procedure to a slice of the deque, fromIndex, inclusive, to + * toIndex, exclusive. + */ + private void forEach(FloatProcedure procedure, int fromIndex, final int toIndex) { + final float[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + procedure.apply(buffer[i]); + } + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + int fromIndex = head; + int toIndex = tail; + + final float[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + if (!predicate.apply(buffer[i])) { + break; + } + } + + return predicate; + } + + /** Applies procedure to all elements of this deque, tail to head. */ + @Override + public T descendingForEach(T procedure) { + descendingForEach(procedure, head, tail); + return procedure; + } + + /** + * Applies procedure to a slice of the deque, toIndex, exclusive, down + * to fromIndex, inclusive. + */ + private void descendingForEach(FloatProcedure procedure, int fromIndex, final int toIndex) { + if (fromIndex == toIndex) return; + + final float[] buffer = this.buffer; + int i = toIndex; + do { + i = oneLeft(i, buffer.length); + procedure.apply(buffer[i]); + } while (i != fromIndex); + } + + /** {@inheritDoc} */ + @Override + public T descendingForEach(T predicate) { + descendingForEach(predicate, head, tail); + return predicate; + } + + /** + * Applies predicate to a slice of the deque, toIndex, exclusive, down + * to fromIndex, inclusive or until the predicate returns false. + */ + private void descendingForEach(FloatPredicate predicate, int fromIndex, final int toIndex) { + if (fromIndex == toIndex) return; + + final float[] buffer = this.buffer; + int i = toIndex; + do { + i = oneLeft(i, buffer.length); + if (!predicate.apply(buffer[i])) { + break; + } + } while (i != fromIndex); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(FloatPredicate predicate) { + final float[] buffer = this.buffer; + final int last = tail; + final int bufLen = buffer.length; + int removed = 0; + int from, to; + from = to = head; + try { + for (from = to = head; from != last; from = oneRight(from, bufLen)) { + if (predicate.apply(buffer[from])) { + buffer[from] = 0f; + removed++; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0f; + } + + to = oneRight(to, bufLen); + } + } finally { + // Keep the deque in consistent state even if the predicate throws an exception. + for (; from != last; from = oneRight(from, bufLen)) { + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0f; + } + + to = oneRight(to, bufLen); + } + tail = to; + } + + return removed; + } + + /** {@inheritDoc} */ + @Override + public boolean contains(float e) { + int fromIndex = head; + int toIndex = tail; + + final float[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + if ((Float.floatToIntBits(e) == Float.floatToIntBits(buffer[i]))) { + return true; + } + } + + return false; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 1; + int fromIndex = head; + int toIndex = tail; + + final float[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + h = 31 * h + BitMixer.mix(this.buffer[i]); + } + return h; + } + + /** + * Returns true only if the other object is an instance of the same class and with + * the same elements. + */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Compare order-aligned elements against another {@link FloatDeque}. */ + protected boolean equalElements(FloatArrayDeque other) { + int max = size(); + if (other.size() != max) { + return false; + } + + Iterator i1 = this.iterator(); + Iterator i2 = other.iterator(); + + while (i1.hasNext() && i2.hasNext()) { + if (!(Float.floatToIntBits(i1.next().value) == Float.floatToIntBits(i2.next().value))) { + return false; + } + } + + return !i1.hasNext() && !i2.hasNext(); + } + + /** Create a new deque by pushing a variable number of arguments to the end of it. */ + public static FloatArrayDeque from(float... elements) { + final FloatArrayDeque coll = new FloatArrayDeque(elements.length); + coll.addLast(elements); + return coll; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/FloatArrayList.java b/src/main/java/com/carrotsearch/hppc/FloatArrayList.java new file mode 100755 index 00000000..0b82dc2a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatArrayList.java @@ -0,0 +1,579 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.FloatPredicate; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** An array-backed list of floats. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java") +public class FloatArrayList extends AbstractFloatCollection + implements FloatIndexedContainer, Preallocable, Cloneable, Accountable { + /** An immutable empty buffer (array). */ + public static final float[] EMPTY_ARRAY = new float[0]; + + ; + + /** Reuse the same strategy instance. */ + private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = + BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; + + /** + * Internal array for storing the list. The array may be larger than the current size ({@link + * #size()}). + */ + public float[] buffer = EMPTY_ARRAY; + + /** Current number of elements stored in {@link #buffer}. */ + public int elementsCount; + + /** Buffer resizing strategy. */ + protected final ArraySizingStrategy resizer; + + /** New instance with sane defaults. */ + public FloatArrayList() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public FloatArrayList(int expectedElements) { + this(expectedElements, DEFAULT_SIZING_STRATEGY); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public FloatArrayList(int expectedElements, ArraySizingStrategy resizer) { + assert resizer != null; + this.resizer = resizer; + buffer = Arrays.copyOf(buffer, expectedElements); + } + + /** Creates a new list from the elements of another container in its iteration order. */ + public FloatArrayList(FloatContainer container) { + this(container.size()); + addAll(container); + } + + /** {@inheritDoc} */ + @Override + public void add(float e1) { + ensureBufferSpace(1); + buffer[elementsCount++] = e1; + } + + /** + * Appends two elements at the end of the list. To add more than two elements, use add + * (vararg-version) or access the buffer directly (tight loop). + */ + public void add(float e1, float e2) { + ensureBufferSpace(2); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + } + + /** Add all elements from a range of given array to the list. */ + public void add(float[] elements, int start, int length) { + assert length >= 0 : "Length must be >= 0"; + + ensureBufferSpace(length); + System.arraycopy(elements, start, buffer, elementsCount, length); + elementsCount += length; + } + + /** + * Vararg-signature method for adding elements at the end of the list. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + */ + public final void add(float... elements) { + add(elements, 0, elements.length); + } + + /** Adds all elements from another container. */ + public int addAll(FloatContainer container) { + final int size = container.size(); + ensureBufferSpace(size); + + for (FloatCursor cursor : container) { + add(cursor.value); + } + + return size; + } + + /** Adds all elements from another iterable. */ + public int addAll(Iterable iterable) { + int size = 0; + for (FloatCursor cursor : iterable) { + add(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public void insert(int index, float e1) { + assert (index >= 0 && index <= size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + "]."; + + ensureBufferSpace(1); + System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index); + buffer[index] = e1; + elementsCount++; + } + + /** {@inheritDoc} */ + @Override + public float get(int index) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + return buffer[index]; + } + + /** {@inheritDoc} */ + @Override + public float set(int index, float e1) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + final float v = buffer[index]; + buffer[index] = e1; + return v; + } + + /** {@inheritDoc} */ + @Override + public float removeAt(int index) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + final float v = buffer[index]; + System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index); + + return v; + } + + /** {@inheritDoc} */ + @Override + public float removeLast() { + assert elementsCount > 0; + + final float v = buffer[--elementsCount]; + + return v; + } + + /** {@inheritDoc} */ + @Override + public void removeRange(int fromIndex, int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex); + final int count = toIndex - fromIndex; + elementsCount -= count; + } + + /** {@inheritDoc} */ + @Override + public boolean removeElement(float e1) { + return removeFirst(e1) != -1; + } + + /** {@inheritDoc} */ + @Override + public int removeFirst(float e1) { + final int index = indexOf(e1); + if (index >= 0) removeAt(index); + return index; + } + + /** {@inheritDoc} */ + @Override + public int removeLast(float e1) { + final int index = lastIndexOf(e1); + if (index >= 0) removeAt(index); + return index; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(float e1) { + int to = 0; + for (int from = 0; from < elementsCount; from++) { + if ((Float.floatToIntBits(e1) == Float.floatToIntBits(buffer[from]))) { + continue; + } + if (to != from) { + buffer[to] = buffer[from]; + } + to++; + } + final int deleted = elementsCount - to; + this.elementsCount = to; + + return deleted; + } + + /** {@inheritDoc} */ + @Override + public boolean contains(float e1) { + return indexOf(e1) >= 0; + } + + /** {@inheritDoc} */ + @Override + public int indexOf(float e1) { + for (int i = 0; i < elementsCount; i++) { + if ((Float.floatToIntBits(e1) == Float.floatToIntBits(buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int lastIndexOf(float e1) { + for (int i = elementsCount - 1; i >= 0; i--) { + if ((Float.floatToIntBits(e1) == Float.floatToIntBits(buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return elementsCount == 0; + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + final int bufferLen = (buffer == null ? 0 : buffer.length); + if (expectedElements > bufferLen) { + ensureBufferSpace(expectedElements - size()); + } + } + + /** + * Ensures the internal buffer has enough free slots to store expectedAdditions. + * Increases internal buffer size if needed. + */ + protected void ensureBufferSpace(int expectedAdditions) { + final int bufferLen = (buffer == null ? 0 : buffer.length); + if (elementsCount + expectedAdditions > bufferLen) { + final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions); + assert newSize >= elementsCount + expectedAdditions + : "Resizer failed to" + + " return sensible new size: " + + newSize + + " <= " + + (elementsCount + expectedAdditions); + + this.buffer = Arrays.copyOf(buffer, newSize); + } + } + + /** + * Truncate or expand the list to the new size. If the list is truncated, the buffer will not be + * reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated + * values will be reset to the default value (zero). If the list is expanded, the elements beyond + * the current size are initialized with JVM-defaults (zero or null values). + */ + public void resize(int newSize) { + if (newSize <= buffer.length) { + if (newSize < elementsCount) { + Arrays.fill(buffer, newSize, elementsCount, 0f); + } else { + Arrays.fill(buffer, elementsCount, newSize, 0f); + } + } else { + ensureCapacity(newSize); + } + this.elementsCount = newSize; + } + + /** {@inheritDoc} */ + @Override + public int size() { + return elementsCount; + } + + /** Trim the internal buffer to the current size. */ + public void trimToSize() { + if (size() != this.buffer.length) { + this.buffer = toArray(); + } + } + + /** + * Sets the number of stored elements to zero. Releases and initializes the internal storage array + * to default values. To clear the list without cleaning the buffer, simply set the {@link + * #elementsCount} field to zero. + */ + @Override + public void clear() { + Arrays.fill(buffer, 0, elementsCount, 0f); + this.elementsCount = 0; + } + + /** Sets the number of stored elements to zero and releases the internal storage array. */ + @Override + public void release() { + this.buffer = EMPTY_ARRAY; + this.elementsCount = 0; + } + + /** + * {@inheritDoc} + * + *

The returned array is sized to match exactly the number of elements of the stack. + */ + @Override + public float[] toArray() { + + return Arrays.copyOf(buffer, elementsCount); + } + + /** {@inheritDoc} */ + @Override + public FloatIndexedContainer sort() { + Arrays.sort(buffer, 0, elementsCount); + return this; + } + + /** {@inheritDoc} */ + @Override + public FloatIndexedContainer reverse() { + for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) { + float tmp = buffer[i]; + buffer[i] = buffer[j]; + buffer[j] = tmp; + } + return this; + } + + /** + * Clone this object. The returned clone will reuse the same hash function and array resizing + * strategy. + */ + @Override + public FloatArrayList clone() { + try { + + final FloatArrayList cloned = (FloatArrayList) super.clone(); + cloned.buffer = buffer.clone(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 1, max = elementsCount; + for (int i = 0; i < max; i++) { + h = 31 * h + BitMixer.mix(this.buffer[i]); + } + return h; + } + + /** + * Returns true only if the other object is an instance of the same class and with + * the same elements. + */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Compare index-aligned elements against another {@link FloatIndexedContainer}. */ + protected boolean equalElements(FloatArrayList other) { + int max = size(); + if (other.size() != max) { + return false; + } + + for (int i = 0; i < max; i++) { + if (!(Float.floatToIntBits(get(i)) == Float.floatToIntBits(other.get(i)))) { + return false; + } + } + + return true; + } + + @Override + public long ramBytesAllocated() { + // int: elementsCount + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES + + resizer.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(buffer); + } + + @Override + public long ramBytesUsed() { + // int: elementsCount + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES + + resizer.ramBytesUsed() + + RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount); + } + + /** An iterator implementation for {@link FloatArrayList#iterator}. */ + static final class ValueIterator extends AbstractIterator { + private final FloatCursor cursor; + + private final float[] buffer; + private final int size; + + public ValueIterator(float[] buffer, int size) { + this.cursor = new FloatCursor(); + this.cursor.index = -1; + this.size = size; + this.buffer = buffer; + } + + @Override + protected FloatCursor fetch() { + if (cursor.index + 1 == size) return done(); + + cursor.value = buffer[++cursor.index]; + return cursor; + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new ValueIterator(buffer, size()); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + return forEach(procedure, 0, size()); + } + + /** + * Applies procedure to a slice of the list, fromIndex, inclusive, to + * toIndex, exclusive. + */ + public T forEach(T procedure, int fromIndex, final int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + final float[] buffer = this.buffer; + for (int i = fromIndex; i < toIndex; i++) { + procedure.apply(buffer[i]); + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(FloatPredicate predicate) { + final float[] buffer = this.buffer; + final int elementsCount = this.elementsCount; + int to = 0; + int from = 0; + try { + for (; from < elementsCount; from++) { + if (predicate.apply(buffer[from])) { + buffer[from] = 0f; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0f; + } + to++; + } + } finally { + // Keep the list in a consistent state, even if the predicate throws an exception. + for (; from < elementsCount; from++) { + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0f; + } + to++; + } + + this.elementsCount = to; + } + + return elementsCount - to; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + return forEach(predicate, 0, size()); + } + + /** + * Applies predicate to a slice of the list, fromIndex, inclusive, to + * toIndex, exclusive, or until predicate returns false. + */ + public T forEach(T predicate, int fromIndex, final int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + final float[] buffer = this.buffer; + for (int i = fromIndex; i < toIndex; i++) { + if (!predicate.apply(buffer[i])) break; + } + + return predicate; + } + + /** + * Create a list from a variable number of arguments or an array of float. The + * elements are copied from the argument to the internal buffer. + */ + public static FloatArrayList from(float... elements) { + final FloatArrayList list = new FloatArrayList(elements.length); + list.add(elements); + return list; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/FloatBufferVisualizer.java b/src/main/java/com/carrotsearch/hppc/FloatBufferVisualizer.java new file mode 100755 index 00000000..d0c471c3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatBufferVisualizer.java @@ -0,0 +1,33 @@ +package com.carrotsearch.hppc; + +/** + * Reused buffer visualization routines. + * + * @see FloatSet#visualizeKeyDistribution(int) + * @see FloatVTypeMap#visualizeKeyDistribution(int) + */ +class FloatBufferVisualizer { + static String visualizeKeyDistribution(float[] buffer, int max, int characters) { + final StringBuilder b = new StringBuilder(); + final char[] chars = ".123456789X".toCharArray(); + for (int i = 1, start = -1; i <= characters; i++) { + int end = (int) ((long) i * max / characters); + + if (start + 1 <= end) { + int taken = 0; + int slots = 0; + for (int slot = start + 1; slot <= end; slot++, slots++) { + if (!(Float.floatToIntBits(buffer[slot]) == 0)) { + taken++; + } + } + b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]); + start = end; + } + } + while (b.length() < characters) { + b.append(' '); + } + return b.toString(); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/FloatCollection.java b/src/main/java/com/carrotsearch/hppc/FloatCollection.java new file mode 100755 index 00000000..491fab8f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatCollection.java @@ -0,0 +1,64 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.predicates.FloatPredicate; + +/** + * A collection allows basic, efficient operations on sets of elements (difference and + * intersection). + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java") +public interface FloatCollection extends FloatContainer { + /** + * Removes all occurrences of e from this collection. + * + * @param e Element to be removed from this collection, if present. + * @return The number of removed elements as a result of this call. + */ + public int removeAll(float e); + + /** + * Removes all elements in this collection that are present in c. + * + * @return Returns the number of removed elements. + */ + public int removeAll(FloatLookupContainer c); + + /** + * Removes all elements in this collection for which the given predicate returns true + * . + * + * @return Returns the number of removed elements. + */ + public int removeAll(FloatPredicate predicate); + + /** + * Keeps all elements in this collection that are present in c. Runs in time + * proportional to the number of elements in this collection. Equivalent of sets intersection. + * + * @return Returns the number of removed elements. + */ + public int retainAll(FloatLookupContainer c); + + /** + * Keeps all elements in this collection for which the given predicate returns true. + * + * @return Returns the number of removed elements. + */ + public int retainAll(FloatPredicate predicate); + + /** + * Removes all elements from this collection. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); +} diff --git a/src/main/java/com/carrotsearch/hppc/FloatContainer.java b/src/main/java/com/carrotsearch/hppc/FloatContainer.java new file mode 100755 index 00000000..83b952bf --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatContainer.java @@ -0,0 +1,76 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.FloatCursor; +import com.carrotsearch.hppc.predicates.FloatPredicate; +import com.carrotsearch.hppc.procedures.FloatProcedure; +import java.util.Iterator; + +/** A generic container holding floats. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java") +public interface FloatContainer extends Iterable { + /** + * Returns an iterator to a cursor traversing the collection. The order of traversal is not + * defined. More than one cursor may be active at a time. The behavior of iterators is undefined + * if structural changes are made to the underlying collection. + * + *

The iterator is implemented as a cursor and it returns the same cursor instance on + * every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current + * list's value (or index in the list) use the cursor's public fields. An example is shown below. + * + *

+   * for (FloatCursor<float> c : container) {
+   *   System.out.println("index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator iterator(); + + /** + * Lookup a given element in the container. This operation has no speed guarantees (may be linear + * with respect to the size of this container). + * + * @return Returns true if this container has an element equal to e. + */ + public boolean contains(float e); + + /** + * Return the current number of elements in this container. The time for calculating the + * container's size may take O(n) time, although implementing classes should try to + * maintain the current size and return in constant time. + */ + public int size(); + + /** Shortcut for size() == 0. */ + public boolean isEmpty(); + + /** + * Copies all elements of this container to an array. + * + *

The returned array is always a copy, regardless of the storage used by the container. + */ + public float[] toArray(); + + /** + * Applies a procedure to all container elements. Returns the argument (any subclass + * of {@link FloatProcedure}. This lets the caller to call methods of the argument by chaining the + * call (even if the argument is an anonymous type) to retrieve computed values, for example + * (IntContainer): + * + *

+   * int count = container.forEach(new IntProcedure() {
+   *   int count; // this is a field declaration in an anonymous class.
+   *
+   *   public void apply(int value) {
+   *     count++;
+   *   }
+   * }).count;
+   * 
+ */ + public T forEach(T procedure); + + /** + * Applies a predicate to container elements as long, as the predicate returns + * true. The iteration is interrupted otherwise. + */ + public T forEach(T predicate); +} diff --git a/src/main/java/com/carrotsearch/hppc/FloatDeque.java b/src/main/java/com/carrotsearch/hppc/FloatDeque.java new file mode 100755 index 00000000..240f3298 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatDeque.java @@ -0,0 +1,77 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.FloatCursor; +import com.carrotsearch.hppc.predicates.FloatPredicate; +import com.carrotsearch.hppc.procedures.FloatProcedure; +import java.util.Deque; +import java.util.Iterator; + +/** + * A linear collection that supports element insertion and removal at both ends. + * + * @see Deque + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java") +public interface FloatDeque extends FloatCollection { + /** + * Removes the first element that equals e. + * + * @return The deleted element's index or -1 if the element was not found. + */ + public int removeFirst(float e); + + /** + * Removes the last element that equals e. + * + * @return The deleted element's index or -1 if the element was not found. + */ + public int removeLast(float e); + + /** Inserts the specified element at the front of this deque. */ + public void addFirst(float e); + + /** Inserts the specified element at the end of this deque. */ + public void addLast(float e); + + /** + * Retrieves and removes the first element of this deque. + * + * @return the head (first) element of this deque. + */ + public float removeFirst(); + + /** + * Retrieves and removes the last element of this deque. + * + * @return the tail of this deque. + */ + public float removeLast(); + + /** + * Retrieves the first element of this deque but does not remove it. + * + * @return the head of this deque. + */ + public float getFirst(); + + /** + * Retrieves the last element of this deque but does not remove it. + * + * @return the head of this deque. + */ + public float getLast(); + + /** + * @return An iterator over elements in this deque in tail-to-head order. + */ + public Iterator descendingIterator(); + + /** Applies a procedure to all elements in tail-to-head order. */ + public T descendingForEach(T procedure); + + /** + * Applies a predicate to container elements as long, as the predicate returns + * true. The iteration is interrupted otherwise. + */ + public T descendingForEach(T predicate); +} diff --git a/src/main/java/com/carrotsearch/hppc/FloatIndexedContainer.java b/src/main/java/com/carrotsearch/hppc/FloatIndexedContainer.java new file mode 100755 index 00000000..f7beda6a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatIndexedContainer.java @@ -0,0 +1,91 @@ +package com.carrotsearch.hppc; + +import java.util.RandomAccess; + +/** + * An indexed container provides random access to elements based on an index. Indexes + * are zero-based. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeIndexedContainer.java") +public interface FloatIndexedContainer extends FloatCollection, RandomAccess { + /** + * Removes the first element that equals e1, returning whether an element has been + * removed. + */ + public boolean removeElement(float e1); + + /** + * Removes the first element that equals e1, returning its deleted position or + * -1 if the element was not found. + */ + public int removeFirst(float e1); + + /** + * Removes the last element that equals e1, returning its deleted position or + * -1 if the element was not found. + */ + public int removeLast(float e1); + + /** + * Returns the index of the first occurrence of the specified element in this list, or -1 if this + * list does not contain the element. + */ + public int indexOf(float e1); + + /** + * Returns the index of the last occurrence of the specified element in this list, or -1 if this + * list does not contain the element. + */ + public int lastIndexOf(float e1); + + /** Adds an element to the end of this container (the last index is incremented by one). */ + public void add(float e1); + + /** + * Inserts the specified element at the specified position in this list. + * + * @param index The index at which the element should be inserted, shifting any existing and + * subsequent elements to the right. + */ + public void insert(int index, float e1); + + /** + * Replaces the element at the specified position in this list with the specified element. + * + * @return Returns the previous value in the list. + */ + public float set(int index, float e1); + + /** + * @return Returns the element at index index from the list. + */ + public float get(int index); + + /** + * Removes the element at the specified position in this container and returns it. + * + * @see #removeFirst + * @see #removeLast + * @see #removeAll + */ + public float removeAt(int index); + + /** Removes and returns the last element of this container. This container must not be empty. */ + public float removeLast(); + + /** + * Removes from this container all of the elements with indexes between fromIndex, + * inclusive, and toIndex, exclusive. + */ + public void removeRange(int fromIndex, int toIndex); + + /** Returns this container elements as a stream. */ + + /** Sorts the elements in this container and returns this container. */ + public FloatIndexedContainer sort(); + + /** Reverses the elements in this container and returns this container. */ + public FloatIndexedContainer reverse(); +} diff --git a/src/main/java/com/carrotsearch/hppc/FloatLookupContainer.java b/src/main/java/com/carrotsearch/hppc/FloatLookupContainer.java new file mode 100755 index 00000000..558f763b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatLookupContainer.java @@ -0,0 +1,12 @@ +package com.carrotsearch.hppc; + +/** + * Marker interface for containers that can check if they contain a given object in at least time + * O(log n) and ideally in amortized constant time O(1). + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeLookupContainer.java") +public interface FloatLookupContainer extends FloatContainer { + public boolean contains(float e); +} diff --git a/src/main/java/com/carrotsearch/hppc/FloatPgmIndex.java b/src/main/java/com/carrotsearch/hppc/FloatPgmIndex.java new file mode 100755 index 00000000..e14cb073 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatPgmIndex.java @@ -0,0 +1,600 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.FloatCursor; +import com.carrotsearch.hppc.procedures.FloatProcedure; +import java.util.Arrays; +import java.util.Iterator; + +/** + * Space-efficient index that enables fast rank/range search operations on a sorted sequence of + * float. + * + *

Implementation of the PGM-Index described at https://pgm.di.unipi.it/, based on the paper + * + *

+ *   Paolo Ferragina and Giorgio Vinciguerra.
+ *   The PGM-index: a fully-dynamic compressed learned index with provable worst-case bounds.
+ *   PVLDB, 13(8): 1162-1175, 2020.
+ * 
+ * + * It provides {@code rank} and {@code range} search operations. {@code indexOf()} is faster than + * B+Tree, and the index is much more compact. {@code contains()} is between 4x to 7x slower than + * {@code IntHashSet#contains()}, but between 2.5x to 3x faster than {@link Arrays#binarySearch}. + * + *

Its compactness (40KB for 200MB of keys) makes it efficient for very large collections, the + * index fitting easily in the L2 cache. The {@code epsilon} parameter should be set according to + * the desired space-time trade-off. A smaller value makes the estimation more precise and the range + * smaller but at the cost of increased space usage. In practice, {@code epsilon} 64 is a good sweet + * spot. + * + *

Internally the index uses an optimal piecewise linear mapping from keys to their position in + * the sorted order. This mapping is represented as a sequence of linear models (segments) which are + * themselves recursively indexed by other piecewise linear mappings. + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypePgmIndex.java") +public class FloatPgmIndex implements Accountable { + + /** Empty immutable FloatPgmIndex. */ + public static final FloatPgmIndex EMPTY = new FloatEmptyPgmIndex(); + + /** + * Epsilon approximation range when searching the list of keys. Controls the size of the returned + * search range, strictly greater than 0. It should be set according to the desired space-time + * trade-off. A smaller value makes the estimation more precise and the range smaller but at the + * cost of increased space usage. + * + *

With EPSILON=64 the benchmark with 200MB of keys shows that this PGM index requires only 2% + * additional memory on average (40KB). It depends on the distribution of the keys. This epsilon + * value is good even for 2MB of keys. With EPSILON=32: +5% speed, but 4x space (160KB). + */ + public static final int EPSILON = 64; + + /** + * Epsilon approximation range for the segments layers. Controls the size of the search range in + * the hierarchical segment lists, strictly greater than 0. + */ + public static final int EPSILON_RECURSIVE = 32; + + /** Size of a key, measured in {@link Integer#BYTES} because the key is stored in an int[]. */ + public static final int KEY_SIZE = + RamUsageEstimator.primitiveSizes.get(float.class) / Integer.BYTES; + + /** 2x {@link #KEY_SIZE}. */ + public static final int DOUBLE_KEY_SIZE = KEY_SIZE * 2; + + /** + * Data size of a segment, measured in {@link Integer#BYTES}, because segments are stored in an + * int[]. + */ + public static final int SEGMENT_DATA_SIZE = KEY_SIZE * 3; + + /** Initial value of the exponential jump when scanning out of the epsilon range. */ + public static final int BEYOND_EPSILON_JUMP = 16; + + /** + * The list of keys for which this index is built. It is sorted and may contain duplicate + * elements. + */ + public final FloatArrayList keys; + + /** The size of the key set. That is, the number of distinct elements in {@link #keys}. */ + public final int size; + + /** The lowest key in {@link #keys}. */ + public final float firstKey; + + /** The highest key in {@link #keys}. */ + public final float lastKey; + + /** The epsilon range used to build this index. */ + public final int epsilon; + + /** The recursive epsilon range used to build this index. */ + public final int epsilonRecursive; + + /** The offsets in {@link #segmentData} of the first segment of each segment level. */ + public final int[] levelOffsets; + + /** The index data. It contains all the segments for all the levels. */ + public final int[] segmentData; + + private FloatPgmIndex( + FloatArrayList keys, + int size, + int epsilon, + int epsilonRecursive, + int[] levelOffsets, + int[] segmentData) { + assert keys.size() > 0; + assert size > 0 && size <= keys.size(); + assert epsilon > 0; + assert epsilonRecursive > 0; + this.keys = keys; + this.size = size; + firstKey = keys.get(0); + lastKey = keys.get(keys.size() - 1); + this.epsilon = epsilon; + this.epsilonRecursive = epsilonRecursive; + this.levelOffsets = levelOffsets; + this.segmentData = segmentData; + } + + /** Empty set constructor. */ + private FloatPgmIndex() { + keys = new FloatArrayList(0); + size = 0; + firstKey = 0f; + lastKey = 0f; + epsilon = 0; + epsilonRecursive = 0; + levelOffsets = new int[0]; + segmentData = levelOffsets; + } + + /** Returns the size of the key set. That is, the number of distinct elements in {@link #keys}. */ + public int size() { + return size; + } + + /** Returns whether this key set is empty. */ + public boolean isEmpty() { + return size() == 0; + } + + /** Returns whether this key set contains the given key. */ + public boolean contains(float key) { + return indexOf(key) >= 0; + } + + /** + * Searches the specified key, and returns its index in the element list. If multiple elements are + * equal to the specified key, there is no guarantee which one will be found. + * + * @return The index of the searched key if it is present; otherwise, {@code (-(insertion + * point) - 1)}. The insertion point is defined as the point at which the key would + * be inserted into the list: the index of the first element greater than the key, or {@link + * #keys}#{@code size()} if all the elements are less than the specified key. Note that this + * guarantees that the return value will be >= 0 if and only if the key is found. + */ + public int indexOf(float key) { + if (key < firstKey) { + return -1; + } + if (key > lastKey) { + return -keys.size() - 1; + } + final int[] segmentData = this.segmentData; + int segmentDataIndex = findSegment(key); + int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData); + int index = + Math.min( + approximateIndex(key, segmentDataIndex, segmentData), + Math.min(nextIntercept, keys.size() - 1)); + assert index >= 0 && index < keys.size(); + float k = keys.get(index); + if (key < k) { + // Scan sequentially before the approximated index, within epsilon range. + final int fromIndex = Math.max(index - epsilon - 1, 0); + while (--index >= fromIndex) { + k = keys.get(index); + if (key > k) { + return -index - 2; + } + if ((Float.floatToIntBits(key) == Float.floatToIntBits(k))) { + return index; + } + } + // Continue scanning out of the epsilon range. + // This might happen in rare cases of precision error during the approximation + // computation for longs (we don't have long double 128 bits in Java). + // This might also happen in rare corner cases of large duplicate elements + // sequence at the epsilon range boundary. + index++; + int jump = BEYOND_EPSILON_JUMP; + do { + int loIndex = Math.max(index - jump, 0); + if (key >= keys.get(loIndex)) { + return Arrays.binarySearch(keys.buffer, loIndex, index, key); + } + index = loIndex; + jump <<= 1; + } while (index > 0); + return -1; + } else if ((Float.floatToIntBits(key) == Float.floatToIntBits(k))) { + return index; + } else { + // Scan sequentially after the approximated index, within epsilon range. + final int toIndex = Math.min(index + epsilon + 3, keys.size()); + while (++index < toIndex) { + k = keys.get(index); + if (key < k) { + return -index - 1; + } + if ((Float.floatToIntBits(key) == Float.floatToIntBits(k))) { + return index; + } + } + // Continue scanning out of the epsilon range. + int jump = BEYOND_EPSILON_JUMP; + do { + int hiIndex = Math.min(index + jump, keys.size()); + if (key <= keys.get(hiIndex)) { + return Arrays.binarySearch(keys.buffer, index, hiIndex, key); + } + index = hiIndex; + jump <<= 1; + } while (index < keys.size()); + return -keys.size() - 1; + } + } + + /** + * Returns, for any value {@code x}, the number of keys in the sorted list which are smaller than + * {@code x}. It is equal to {@link #indexOf} if {@code x} belongs to the list, or -{@link + * #indexOf}-1 otherwise. + * + *

If multiple elements are equal to the specified key, there is no guarantee which one will be + * found. + * + * @return The index of the searched key if it is present; otherwise, the {@code insertion point}. + * The insertion point is defined as the point at which the key would be inserted into + * the list: the index of the first element greater than the key, or {@link #keys}#{@code + * size()} if all the elements are less than the specified key. Note that this method always + * returns a value >= 0. + */ + public int rank(float x) { + int index = indexOf(x); + return index >= 0 ? index : -index - 1; + } + + /** + * Returns the number of keys in the list that are greater than or equal to {@code minKey} + * (inclusive), and less than or equal to {@code maxKey} (inclusive). + */ + public int rangeCardinality(float minKey, float maxKey) { + int fromIndex = rank(minKey); + int maxIndex = indexOf(maxKey); + int toIndex = maxIndex >= 0 ? maxIndex + 1 : -maxIndex - 1; + return Math.max(toIndex - fromIndex, 0); + } + + /** + * Returns an iterator over the keys in the list that are greater than or equal to {@code minKey} + * (inclusive), and less than or equal to {@code maxKey} (inclusive). + */ + public Iterator rangeIterator(float minKey, float maxKey) { + int fromIndex = rank(minKey); + return new RangeIterator(keys, fromIndex, maxKey); + } + + /** + * Applies {@code procedure} to the keys in the list that are greater than or equal to {@code + * minKey} (inclusive), and less than or equal to {@code maxKey} (inclusive). + */ + public T forEachInRange(T procedure, float minKey, float maxKey) { + final float[] buffer = keys.buffer; + float k; + for (int i = rank(minKey), size = keys.size(); i < size && (k = buffer[i]) <= maxKey; i++) { + procedure.apply(k); + } + return procedure; + } + + /** + * Estimates the allocated memory. It does not count the memory for the list of keys, only for the + * index itself. + */ + @Override + public long ramBytesAllocated() { + // int: size, epsilon, epsilonRecursive + // float: firstKey, lastKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 3 * Integer.BYTES + + 2L * KEY_SIZE * Integer.BYTES + // + keys.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(levelOffsets) + + RamUsageEstimator.shallowSizeOfArray(segmentData); + } + + /** + * Estimates the bytes that are actually used. It does not count the memory for the list of keys, + * only for the index itself. + */ + @Override + public long ramBytesUsed() { + // int: size, epsilon, epsilonRecursive + // float: firstKey, lastKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 3 * Integer.BYTES + + 2L * KEY_SIZE * Integer.BYTES + // + keys.ramBytesUsed() + + RamUsageEstimator.shallowSizeOfArray(levelOffsets) + + RamUsageEstimator.shallowSizeOfArray(segmentData); + } + + /** + * Finds the segment responsible for a given key, that is, the rightmost segment having its first + * key <= the searched key. + * + * @return the segment data index; or -1 if none. + */ + private int findSegment(float key) { + assert key >= firstKey && key <= lastKey; + final int epsilonRecursive = this.epsilonRecursive; + final int[] levelOffsets = this.levelOffsets; + final int[] segmentData = this.segmentData; + int level = levelOffsets.length - 1; + int segmentDataIndex = levelOffsets[level] * SEGMENT_DATA_SIZE; + while (--level >= 0) { + int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData); + int index = Math.min(approximateIndex(key, segmentDataIndex, segmentData), nextIntercept); + assert index >= 0 && index <= levelOffsets[level + 1] - levelOffsets[level] - 1; + int sdIndex = (levelOffsets[level] + index) * SEGMENT_DATA_SIZE; + if (getKey(sdIndex, segmentData) <= key) { + // Scan sequentially segments after the approximated index, within the epsilon range. + final int levelNumSegments = levelOffsets[level + 1] - levelOffsets[level] - 1; + final int toIndex = Math.min(index + epsilonRecursive + 3, levelNumSegments); + while (index++ < toIndex && getKey(sdIndex + SEGMENT_DATA_SIZE, segmentData) <= key) { + sdIndex += SEGMENT_DATA_SIZE; + } + } else { + // Scan sequentially segments before the approximated index, within the epsilon range. + final int fromIndex = Math.max(index - epsilonRecursive - 1, 0); + while (index-- > fromIndex) { + sdIndex -= SEGMENT_DATA_SIZE; + if (getKey(sdIndex, segmentData) <= key) { + break; + } + } + } + segmentDataIndex = sdIndex; + } + assert segmentDataIndex >= 0; + return segmentDataIndex; + } + + private int approximateIndex(float key, int segmentDataIndex, int[] segmentData) { + long intercept = getIntercept(segmentDataIndex, segmentData); + float sKey = getKey(segmentDataIndex, segmentData); + double slope = getSlope(segmentDataIndex, segmentData); + int index = (int) (slope * ((double) key - sKey) + intercept); + return Math.max(index, 0); + } + + private static long getIntercept(int segmentDataIndex, int[] segmentData) { + return PgmIndexUtil.getIntercept(segmentDataIndex, segmentData, KEY_SIZE); + } + + private float getKey(int segmentDataIndex, int[] segmentData) { + return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0f); + } + + private static double getSlope(int segmentDataIndex, int[] segmentData) { + return PgmIndexUtil.getSlope(segmentDataIndex + DOUBLE_KEY_SIZE, segmentData, KEY_SIZE); + } + + /** Empty immutable PGM Index. */ + private static class FloatEmptyPgmIndex extends FloatPgmIndex { + + private final Iterator emptyIterator = new FloatEmptyIterator(); + + @Override + public int indexOf(float key) { + return -1; + } + + @Override + public Iterator rangeIterator(float minKey, float maxKey) { + return emptyIterator; + } + + @Override + public T forEachInRange(T procedure, float minKey, float maxKey) { + return procedure; + } + + private static class FloatEmptyIterator extends AbstractIterator { + @Override + protected FloatCursor fetch() { + return done(); + } + } + } + + /** Iterator over a range of elements in a sorted array. */ + protected static class RangeIterator extends AbstractIterator { + private final float[] buffer; + private final int size; + private final FloatCursor cursor; + private final float maxKey; + + /** Range iterator from {@code fromIndex} (inclusive) to {@code maxKey} (inclusive). */ + protected RangeIterator(FloatArrayList keys, int fromIndex, float maxKey) { + this.buffer = keys.buffer; + this.size = keys.size(); + this.cursor = new FloatCursor(); + this.cursor.index = fromIndex; + this.maxKey = maxKey; + } + + @Override + protected FloatCursor fetch() { + if (cursor.index >= size) { + return done(); + } + cursor.value = buffer[cursor.index++]; + if (cursor.value > maxKey) { + cursor.index = size; + return done(); + } + return cursor; + } + } + + /** Builds a {@link FloatPgmIndex} on a provided sorted list of keys. */ + public static class FloatBuilder implements PlaModel.SegmentConsumer, Accountable { + + protected FloatArrayList keys; + protected int epsilon = EPSILON; + protected int epsilonRecursive = EPSILON_RECURSIVE; + protected PlaModel plam; + protected int size; + protected IntArrayList segmentData; + protected int numSegments; + + /** Sets the sorted list of keys to build the index for; duplicate elements are allowed. */ + public FloatBuilder setSortedKeys(FloatArrayList keys) { + this.keys = keys; + return this; + } + + /** Sets the sorted array of keys to build the index for; duplicate elements are allowed. */ + public FloatBuilder setSortedKeys(float[] keys, int length) { + FloatArrayList keyList = new FloatArrayList(0); + keyList.buffer = keys; + keyList.elementsCount = length; + return setSortedKeys(keyList); + } + + /** Sets the epsilon range to use when learning the segments for the list of keys. */ + public FloatBuilder setEpsilon(int epsilon) { + if (epsilon <= 0) { + throw new IllegalArgumentException("epsilon must be > 0"); + } + this.epsilon = epsilon; + return this; + } + + /** + * Sets the recursive epsilon range to use when learning the segments for the segment levels. + */ + public FloatBuilder setEpsilonRecursive(int epsilonRecursive) { + if (epsilonRecursive <= 0) { + throw new IllegalArgumentException("epsilonRecursive must be > 0"); + } + this.epsilonRecursive = epsilonRecursive; + return this; + } + + /** Builds the {@link FloatPgmIndex}; or {@link #EMPTY} if there are no keys in the list. */ + public FloatPgmIndex build() { + if (keys == null || keys.size() == 0) { + return (FloatPgmIndex) EMPTY; + } + plam = new PlaModel(epsilon); + + int segmentsInitialCapacity = + Math.min( + Math.max(keys.size() / (2 * epsilon * epsilon) * SEGMENT_DATA_SIZE, 16), 1 << 19); + segmentData = new IntArrayList(segmentsInitialCapacity); + IntArrayList levelOffsets = new IntArrayList(16); + + int levelOffset = 0; + levelOffsets.add(levelOffset); + int levelNumSegments = buildFirstLevel(); + while (levelNumSegments > 1) { + int nextLevelOffset = numSegments; + levelOffsets.add(nextLevelOffset); + levelNumSegments = buildUpperLevel(levelOffset, levelNumSegments); + levelOffset = nextLevelOffset; + } + + int[] segmentDataFinal = segmentData.toArray(); + int[] levelOffsetsFinal = levelOffsets.toArray(); + return new FloatPgmIndex( + keys, size, epsilon, epsilonRecursive, levelOffsetsFinal, segmentDataFinal); + } + + private int buildFirstLevel() { + assert numSegments == 0; + int numKeys = keys.size(); + int size = 0; + float key = keys.get(0); + size++; + plam.addKey(key, 0, this); + for (int i = 1; i < numKeys; i++) { + float nextKey = keys.get(i); + if (!(Float.floatToIntBits(nextKey) == Float.floatToIntBits(key))) { + key = nextKey; + plam.addKey(key, i, this); + size++; + } + } + plam.finish(this); + addSentinelSegment(numKeys); + this.size = size; + return numSegments - 1; + } + + private int buildUpperLevel(int levelOffset, int levelNumSegments) { + plam.setEpsilon(epsilonRecursive); + assert numSegments > 0; + int initialNumSegments = numSegments; + int segmentDataIndex = levelOffset * SEGMENT_DATA_SIZE; + float key = getKey(segmentDataIndex, segmentData.buffer); + plam.addKey(key, 0, this); + for (int i = 1; i < levelNumSegments; i++) { + segmentDataIndex += SEGMENT_DATA_SIZE; + float nextKey = getKey(segmentDataIndex, segmentData.buffer); + if (!(Float.floatToIntBits(nextKey) == Float.floatToIntBits(key))) { + key = nextKey; + plam.addKey(key, i, this); + } + } + plam.finish(this); + addSentinelSegment(levelNumSegments); + return numSegments - initialNumSegments - 1; + } + + private float getKey(int segmentDataIndex, int[] segmentData) { + return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0f); + } + + /** + * Adds a sentinel segment that is used to give a limit for the position approximation, but does + * not count in the number of segments per level. + */ + private void addSentinelSegment(int endIndex) { + // This sentinel segment is used in findSegment(). + accept(Double.MAX_VALUE, 0d, endIndex); + } + + @Override + public void accept(double firstKey, double slope, long intercept) { + PgmIndexUtil.addIntercept(intercept, segmentData, KEY_SIZE); + PgmIndexUtil.addKey((float) firstKey, segmentData); + PgmIndexUtil.addSlope(slope, segmentData, KEY_SIZE); + numSegments++; + assert segmentData.size() == numSegments * SEGMENT_DATA_SIZE; + } + + /** + * Estimates the allocated memory. It does not count the memory for the list of keys, only for + * the builder itself. + */ + @Override + public long ramBytesAllocated() { + // int: epsilon, epsilonRecursive, size, numSegments + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + // + keys.ramBytesAllocated() + + plam.ramBytesAllocated() + + segmentData.ramBytesAllocated(); + } + + /** + * Estimates the bytes that are actually used. It does not count the memory for the list of + * keys, only for the builder itself. + */ + @Override + public long ramBytesUsed() { + // int: epsilon, epsilonRecursive, size, numSegments + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + // + keys.ramBytesUsed() + + plam.ramBytesUsed() + + segmentData.ramBytesUsed(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/FloatStack.java b/src/main/java/com/carrotsearch/hppc/FloatStack.java new file mode 100755 index 00000000..d2377178 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatStack.java @@ -0,0 +1,137 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.FloatCursor; + +/** + * A subclass of {@link FloatArrayList} adding stack-related utility methods. The top of the stack + * is at the {@link #size()} - 1 element. + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java") +public class FloatStack extends FloatArrayList { + /** New instance with sane defaults. */ + public FloatStack() { + super(); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public FloatStack(int expectedElements) { + super(expectedElements); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public FloatStack(int expectedElements, ArraySizingStrategy resizer) { + super(expectedElements, resizer); + } + + /** Create a stack by pushing all elements of another container to it. */ + public FloatStack(FloatContainer container) { + super(container); + } + + /** Adds one float to the stack. */ + public void push(float e1) { + ensureBufferSpace(1); + buffer[elementsCount++] = e1; + } + + /** Adds two floats to the stack. */ + public void push(float e1, float e2) { + ensureBufferSpace(2); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + } + + /** Adds three floats to the stack. */ + public void push(float e1, float e2, float e3) { + ensureBufferSpace(3); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + buffer[elementsCount++] = e3; + } + + /** Adds four floats to the stack. */ + public void push(float e1, float e2, float e3, float e4) { + ensureBufferSpace(4); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + buffer[elementsCount++] = e3; + buffer[elementsCount++] = e4; + } + + /** Add a range of array elements to the stack. */ + public void push(float[] elements, int start, int len) { + assert start >= 0 && len >= 0; + + ensureBufferSpace(len); + System.arraycopy(elements, start, buffer, elementsCount, len); + elementsCount += len; + } + + /** + * Vararg-signature method for pushing elements at the top of the stack. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + */ + public final void push(float... elements) { + push(elements, 0, elements.length); + } + + /** Pushes all elements from another container to the top of the stack. */ + public int pushAll(FloatContainer container) { + return addAll(container); + } + + /** Pushes all elements from another iterable to the top of the stack. */ + public int pushAll(Iterable iterable) { + return addAll(iterable); + } + + /** Discard an arbitrary number of elements from the top of the stack. */ + public void discard(int count) { + assert elementsCount >= count; + + elementsCount -= count; + } + + /** Discard the top element from the stack. */ + public void discard() { + assert elementsCount > 0; + + elementsCount--; + } + + /** Remove the top element from the stack and return it. */ + public float pop() { + return removeLast(); + } + + /** Peek at the top element on the stack. */ + public float peek() { + assert elementsCount > 0; + return buffer[elementsCount - 1]; + } + + /** Create a stack by pushing a variable number of arguments to it. */ + public static FloatStack from(float... elements) { + final FloatStack stack = new FloatStack(elements.length); + stack.push(elements); + return stack; + } + + /** {@inheritDoc} */ + @Override + public FloatStack clone() { + return (FloatStack) super.clone(); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/Generated.java b/src/main/java/com/carrotsearch/hppc/Generated.java new file mode 100755 index 00000000..dd8c66d2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/Generated.java @@ -0,0 +1,37 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Documented +@Retention(SOURCE) +@Target({PACKAGE, TYPE, ANNOTATION_TYPE, METHOD, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, PARAMETER}) +public @interface Generated { + /** + * The value element MUST have the name of the code generator. The recommended convention is to + * use the fully qualified name of the code generator. For example: com.acme.generator.CodeGen. + */ + String[] value(); + + /** Date when the source was generated. */ + String date() default ""; + + /** + * A place holder for any comments that the code generator may want to include in the generated + * code. + */ + String comments() default ""; +} diff --git a/src/main/java/com/carrotsearch/hppc/HashContainers.java b/src/main/java/com/carrotsearch/hppc/HashContainers.java new file mode 100755 index 00000000..7f4be809 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/HashContainers.java @@ -0,0 +1,112 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc; + +import java.util.concurrent.atomic.AtomicInteger; + +public final class HashContainers { + /** + * Maximum array size for hash containers (power-of-two and still allocable in Java, not a + * negative int). + */ + public static final int MAX_HASH_ARRAY_LENGTH = 0x80000000 >>> 1; + + /** Minimum hash buffer size. */ + public static final int MIN_HASH_ARRAY_LENGTH = 4; + + /** Default load factor. */ + public static final float DEFAULT_LOAD_FACTOR = 0.75f; + + /** Minimal sane load factor (99 empty slots per 100). */ + public static final float MIN_LOAD_FACTOR = 1 / 100.0f; + + /** Maximum sane load factor (1 empty slot per 100). */ + public static final float MAX_LOAD_FACTOR = 99 / 100.0f; + + private static final AtomicInteger ITERATION_SEED = new AtomicInteger(); + + /** + * Compute and return the maximum number of elements (inclusive) that can be stored in a hash + * container for a given load factor. + */ + public static int maxElements(double loadFactor) { + checkLoadFactor(loadFactor, 0, 1); + return expandAtCount(MAX_HASH_ARRAY_LENGTH, loadFactor) - 1; + } + + /** */ + static int minBufferSize(int elements, double loadFactor) { + if (elements < 0) { + throw new IllegalArgumentException("Number of elements must be >= 0: " + elements); + } + + long length = (long) Math.ceil(elements / loadFactor); + if (length == elements) { + length++; + } + length = Math.max(MIN_HASH_ARRAY_LENGTH, BitUtil.nextHighestPowerOfTwo(length)); + + if (length > MAX_HASH_ARRAY_LENGTH) { + throw new BufferAllocationException( + "Maximum array size exceeded for this load factor (elements: %d, load factor: %f)", + elements, loadFactor); + } + + return (int) length; + } + + /** */ + static int nextBufferSize(int arraySize, int elements, double loadFactor) { + assert checkPowerOfTwo(arraySize); + if (arraySize == MAX_HASH_ARRAY_LENGTH) { + throw new BufferAllocationException( + "Maximum array size exceeded for this load factor (elements: %d, load factor: %f)", + elements, loadFactor); + } + + return (int) arraySize << 1; + } + + /** */ + static int expandAtCount(int arraySize, double loadFactor) { + assert checkPowerOfTwo(arraySize); + // Take care of hash container invariant (there has to be at least one empty slot to ensure + // the lookup loop finds either the element or an empty slot). + return Math.min(arraySize - 1, (int) Math.ceil(arraySize * loadFactor)); + } + + /** */ + static void checkLoadFactor( + double loadFactor, double minAllowedInclusive, double maxAllowedInclusive) { + if (loadFactor < minAllowedInclusive || loadFactor > maxAllowedInclusive) { + throw new BufferAllocationException( + "The load factor should be in range [%.2f, %.2f]: %f", + minAllowedInclusive, maxAllowedInclusive, loadFactor); + } + } + + /** */ + static boolean checkPowerOfTwo(int arraySize) { + // These are internals, we can just assert without retrying. + assert arraySize > 1; + assert BitUtil.nextHighestPowerOfTwo(arraySize) == arraySize; + return true; + } + + /** Provides the next hash iteration order seed. It is simply an incrementing atomic counter. */ + static int nextIterationSeed() { + return ITERATION_SEED.incrementAndGet(); + } + + /** Computes a hash iteration order increment based on the provided seed. */ + static int iterationIncrement(int seed) { + return 29 + ((seed & 7) << 1); // Small odd integer. + } +} diff --git a/src/main/java/com/carrotsearch/hppc/IntArrayDeque.java b/src/main/java/com/carrotsearch/hppc/IntArrayDeque.java new file mode 100755 index 00000000..06983d90 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntArrayDeque.java @@ -0,0 +1,776 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; + +import com.carrotsearch.hppc.cursors.IntCursor; +import com.carrotsearch.hppc.predicates.IntPredicate; +import com.carrotsearch.hppc.procedures.IntProcedure; +import java.util.*; + +/** An array-backed {@link IntDeque}. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java") +public class IntArrayDeque extends AbstractIntCollection + implements IntDeque, Preallocable, Cloneable, Accountable { + + /** Reuse the same strategy instance. */ + private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = + BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; + + /** Internal array for storing elements of the deque. */ + public int[] buffer = IntArrayList.EMPTY_ARRAY; + + /** + * The index of the element at the head of the deque or an arbitrary number equal to tail if the + * deque is empty. + */ + public int head; + + /** The index at which the next element would be added to the tail of the deque. */ + public int tail; + + /** Buffer resizing strategy. */ + protected final ArraySizingStrategy resizer; + + /** New instance with sane defaults. */ + public IntArrayDeque() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public IntArrayDeque(int expectedElements) { + this(expectedElements, DEFAULT_SIZING_STRATEGY); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public IntArrayDeque(int expectedElements, ArraySizingStrategy resizer) { + assert resizer != null; + this.resizer = resizer; + ensureCapacity(expectedElements); + } + + /** + * Creates a new deque from elements of another container, appending elements at the end of the + * deque in the iteration order. + */ + public IntArrayDeque(IntContainer container) { + this(container.size()); + addLast(container); + } + + /** {@inheritDoc} */ + @Override + public void addFirst(int e1) { + int h = oneLeft(head, buffer.length); + if (h == tail) { + ensureBufferSpace(1); + h = oneLeft(head, buffer.length); + } + buffer[head = h] = e1; + } + + /** + * Vararg-signature method for adding elements at the front of this deque. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + * + * @param elements The elements to add. + */ + public final void addFirst(int... elements) { + ensureBufferSpace(elements.length); + for (int k : elements) { + addFirst(k); + } + } + + /** + * Inserts all elements from the given container to the front of this deque. + * + * @param container The container to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addFirst(IntContainer container) { + int size = container.size(); + ensureBufferSpace(size); + + for (IntCursor cursor : container) { + addFirst(cursor.value); + } + + return size; + } + + /** + * Inserts all elements from the given iterable to the front of this deque. + * + * @param iterable The iterable to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addFirst(Iterable iterable) { + int size = 0; + for (IntCursor cursor : iterable) { + addFirst(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public void addLast(int e1) { + int t = oneRight(tail, buffer.length); + if (head == t) { + ensureBufferSpace(1); + t = oneRight(tail, buffer.length); + } + buffer[tail] = e1; + tail = t; + } + + /** + * Vararg-signature method for adding elements at the end of this deque. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + * + * @param elements The elements to iterate over. + */ + public final void addLast(int... elements) { + ensureBufferSpace(1); + for (int k : elements) { + addLast(k); + } + } + + /** + * Inserts all elements from the given container to the end of this deque. + * + * @param container The container to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addLast(IntContainer container) { + int size = container.size(); + ensureBufferSpace(size); + + for (IntCursor cursor : container) { + addLast(cursor.value); + } + + return size; + } + + /** + * Inserts all elements from the given iterable to the end of this deque. + * + * @param iterable The iterable to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addLast(Iterable iterable) { + int size = 0; + for (IntCursor cursor : iterable) { + addLast(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public int removeFirst() { + assert size() > 0 : "The deque is empty."; + + final int result = buffer[head]; + buffer[head] = 0; + head = oneRight(head, buffer.length); + return result; + } + + /** {@inheritDoc} */ + @Override + public int removeLast() { + assert size() > 0 : "The deque is empty."; + + tail = oneLeft(tail, buffer.length); + final int result = buffer[tail]; + buffer[tail] = 0; + return result; + } + + /** {@inheritDoc} */ + @Override + public int getFirst() { + assert size() > 0 : "The deque is empty."; + + return buffer[head]; + } + + /** {@inheritDoc} */ + @Override + public int getLast() { + assert size() > 0 : "The deque is empty."; + + return buffer[oneLeft(tail, buffer.length)]; + } + + /** {@inheritDoc} */ + @Override + public int removeFirst(int e1) { + final int index = bufferIndexOf(e1); + if (index >= 0) removeAtBufferIndex(index); + return index; + } + + /** + * Return the index of the first (counting from head) element equal to e1. The index + * points to the {@link #buffer} array. + * + * @param e1 The element to look for. + * @return Returns the index of the first element equal to e1 or -1 if + * not found. + */ + public int bufferIndexOf(int e1) { + final int last = tail; + final int bufLen = buffer.length; + for (int i = head; i != last; i = oneRight(i, bufLen)) { + if (((e1) == (buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int removeLast(int e1) { + final int index = lastBufferIndexOf(e1); + if (index >= 0) { + removeAtBufferIndex(index); + } + return index; + } + + /** + * Return the index of the last (counting from tail) element equal to e1. The index + * points to the {@link #buffer} array. + * + * @param e1 The element to look for. + * @return Returns the index of the first element equal to e1 or -1 if + * not found. + */ + public int lastBufferIndexOf(int e1) { + final int bufLen = buffer.length; + final int last = oneLeft(head, bufLen); + for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) { + if (((e1) == (buffer[i]))) return i; + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(int e1) { + int removed = 0; + final int last = tail; + final int bufLen = buffer.length; + int from, to; + for (from = to = head; from != last; from = oneRight(from, bufLen)) { + if (((e1) == (buffer[from]))) { + buffer[from] = 0; + removed++; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0; + } + + to = oneRight(to, bufLen); + } + + tail = to; + return removed; + } + + /** + * Removes the element at index in the internal {#link {@link #buffer} array, + * returning its value. + * + * @param index Index of the element to remove. The index must be located between {@link #head} + * and {@link #tail} in modulo {@link #buffer} arithmetic. + */ + public void removeAtBufferIndex(int index) { + assert (head <= tail ? index >= head && index < tail : index >= head || index < tail) + : "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ")."; + + // Cache fields in locals (hopefully moved to registers). + final int[] buffer = this.buffer; + final int bufLen = buffer.length; + final int lastIndex = bufLen - 1; + final int head = this.head; + final int tail = this.tail; + + final int leftChunk = Math.abs(index - head) % bufLen; + final int rightChunk = Math.abs(tail - index) % bufLen; + + if (leftChunk < rightChunk) { + if (index >= head) { + System.arraycopy(buffer, head, buffer, head + 1, leftChunk); + } else { + System.arraycopy(buffer, 0, buffer, 1, index); + buffer[0] = buffer[lastIndex]; + System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head); + } + buffer[head] = 0; + this.head = oneRight(head, bufLen); + } else { + if (index < tail) { + System.arraycopy(buffer, index + 1, buffer, index, rightChunk); + } else { + System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index); + buffer[lastIndex] = buffer[0]; + System.arraycopy(buffer, 1, buffer, 0, tail); + } + buffer[tail] = 0; + this.tail = oneLeft(tail, bufLen); + } + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int size() { + if (head <= tail) return tail - head; + else return (tail - head + buffer.length); + } + + /** + * {@inheritDoc} + * + *

The internal array buffers are not released as a result of this call. + * + * @see #release() + */ + @Override + public void clear() { + if (head < tail) { + Arrays.fill(buffer, head, tail, 0); + } else { + Arrays.fill(buffer, 0, tail, 0); + Arrays.fill(buffer, head, buffer.length, 0); + } + this.head = tail = 0; + } + + /** Release internal buffers of this deque and reallocate with the default buffer. */ + public void release() { + this.head = tail = 0; + buffer = IntArrayList.EMPTY_ARRAY; + ensureBufferSpace(0); + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + ensureBufferSpace(expectedElements - size()); + } + + /** + * Ensures the internal buffer has enough free slots to store expectedAdditions. + * Increases internal buffer size if needed. + */ + protected void ensureBufferSpace(int expectedAdditions) { + final int bufferLen = buffer.length; + final int elementsCount = size(); + + if (elementsCount + expectedAdditions >= bufferLen) { + final int emptySlot = 1; // deque invariant: always an empty slot. + final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions); + assert newSize >= (elementsCount + expectedAdditions + emptySlot) + : "Resizer failed to" + + " return sensible new size: " + + newSize + + " <= " + + (elementsCount + expectedAdditions); + + try { + final int[] newBuffer = (new int[newSize]); + if (bufferLen > 0) { + toArray(newBuffer); + tail = elementsCount; + head = 0; + } + this.buffer = newBuffer; + } catch (OutOfMemoryError e) { + throw new BufferAllocationException( + "Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize); + } + } + } + + /** {@inheritDoc} */ + @Override + public int[] toArray() { + + final int size = size(); + return toArray((new int[size])); + } + + /** + * Copies elements of this deque to an array. The content of the target array is + * filled from index 0 (head of the queue) to index size() - 1 (tail of the queue). + * + * @param target The target array must be large enough to hold all elements. + * @return Returns the target argument for chaining. + */ + public int[] toArray(int[] target) { + assert target.length >= size() : "Target array must be >= " + size(); + + if (head < tail) { + // The contents is not wrapped around. Just copy. + System.arraycopy(buffer, head, target, 0, size()); + } else if (head > tail) { + // The contents is split. Merge elements from the following indexes: + // [head...buffer.length - 1][0, tail - 1] + final int rightCount = buffer.length - head; + System.arraycopy(buffer, head, target, 0, rightCount); + System.arraycopy(buffer, 0, target, rightCount, tail); + } + + return target; + } + + /** + * Clone this object. The returned clone will reuse the same hash function and array resizing + * strategy. + */ + @Override + public IntArrayDeque clone() { + try { + + IntArrayDeque cloned = (IntArrayDeque) super.clone(); + cloned.buffer = buffer.clone(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Move one index to the left, wrapping around buffer. */ + protected static int oneLeft(int index, int modulus) { + if (index >= 1) { + return index - 1; + } + return modulus - 1; + } + + /** Move one index to the right, wrapping around buffer. */ + protected static int oneRight(int index, int modulus) { + if (index + 1 == modulus) { + return 0; + } + return index + 1; + } + + @Override + public long ramBytesAllocated() { + // int: head, tail + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES * 2 + + resizer.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(buffer); + } + + @Override + public long ramBytesUsed() { + // int: head, tail + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES * 2 + + resizer.ramBytesUsed() + + RamUsageEstimator.shallowUsedSizeOfArray(buffer, size()); + } + + /** An iterator implementation for {@link ObjectArrayDeque#iterator}. */ + private final class ValueIterator extends AbstractIterator { + private final IntCursor cursor; + private int remaining; + + public ValueIterator() { + cursor = new IntCursor(); + cursor.index = oneLeft(head, buffer.length); + this.remaining = size(); + } + + @Override + protected IntCursor fetch() { + if (remaining == 0) { + return done(); + } + + remaining--; + cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)]; + return cursor; + } + } + + /** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */ + private final class DescendingValueIterator extends AbstractIterator { + private final IntCursor cursor; + private int remaining; + + public DescendingValueIterator() { + cursor = new IntCursor(); + cursor.index = tail; + this.remaining = size(); + } + + @Override + protected IntCursor fetch() { + if (remaining == 0) return done(); + + remaining--; + cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)]; + return cursor; + } + } + + /** + * Returns a cursor over the values of this deque (in head to tail order). The iterator is + * implemented as a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in + * the deque's buffer) use the cursor's public fields. An example is shown below. + * + *

+   * for (IntValueCursor c : intDeque) {
+   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator iterator() { + return new ValueIterator(); + } + + /** + * Returns a cursor over the values of this deque (in tail to head order). The iterator is + * implemented as a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in + * the deque's buffer) use the cursor's public fields. An example is shown below. + * + *
+   * for (Iterator<IntCursor> i = intDeque.descendingIterator(); i.hasNext();) {
+   *   final IntCursor c = i.next();
+   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator descendingIterator() { + return new DescendingValueIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + forEach(procedure, head, tail); + return procedure; + } + + /** + * Applies procedure to a slice of the deque, fromIndex, inclusive, to + * toIndex, exclusive. + */ + private void forEach(IntProcedure procedure, int fromIndex, final int toIndex) { + final int[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + procedure.apply(buffer[i]); + } + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + int fromIndex = head; + int toIndex = tail; + + final int[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + if (!predicate.apply(buffer[i])) { + break; + } + } + + return predicate; + } + + /** Applies procedure to all elements of this deque, tail to head. */ + @Override + public T descendingForEach(T procedure) { + descendingForEach(procedure, head, tail); + return procedure; + } + + /** + * Applies procedure to a slice of the deque, toIndex, exclusive, down + * to fromIndex, inclusive. + */ + private void descendingForEach(IntProcedure procedure, int fromIndex, final int toIndex) { + if (fromIndex == toIndex) return; + + final int[] buffer = this.buffer; + int i = toIndex; + do { + i = oneLeft(i, buffer.length); + procedure.apply(buffer[i]); + } while (i != fromIndex); + } + + /** {@inheritDoc} */ + @Override + public T descendingForEach(T predicate) { + descendingForEach(predicate, head, tail); + return predicate; + } + + /** + * Applies predicate to a slice of the deque, toIndex, exclusive, down + * to fromIndex, inclusive or until the predicate returns false. + */ + private void descendingForEach(IntPredicate predicate, int fromIndex, final int toIndex) { + if (fromIndex == toIndex) return; + + final int[] buffer = this.buffer; + int i = toIndex; + do { + i = oneLeft(i, buffer.length); + if (!predicate.apply(buffer[i])) { + break; + } + } while (i != fromIndex); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntPredicate predicate) { + final int[] buffer = this.buffer; + final int last = tail; + final int bufLen = buffer.length; + int removed = 0; + int from, to; + from = to = head; + try { + for (from = to = head; from != last; from = oneRight(from, bufLen)) { + if (predicate.apply(buffer[from])) { + buffer[from] = 0; + removed++; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0; + } + + to = oneRight(to, bufLen); + } + } finally { + // Keep the deque in consistent state even if the predicate throws an exception. + for (; from != last; from = oneRight(from, bufLen)) { + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0; + } + + to = oneRight(to, bufLen); + } + tail = to; + } + + return removed; + } + + /** {@inheritDoc} */ + @Override + public boolean contains(int e) { + int fromIndex = head; + int toIndex = tail; + + final int[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + if (((e) == (buffer[i]))) { + return true; + } + } + + return false; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 1; + int fromIndex = head; + int toIndex = tail; + + final int[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + h = 31 * h + BitMixer.mix(this.buffer[i]); + } + return h; + } + + /** + * Returns true only if the other object is an instance of the same class and with + * the same elements. + */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Compare order-aligned elements against another {@link IntDeque}. */ + protected boolean equalElements(IntArrayDeque other) { + int max = size(); + if (other.size() != max) { + return false; + } + + Iterator i1 = this.iterator(); + Iterator i2 = other.iterator(); + + while (i1.hasNext() && i2.hasNext()) { + if (!((i1.next().value) == (i2.next().value))) { + return false; + } + } + + return !i1.hasNext() && !i2.hasNext(); + } + + /** Create a new deque by pushing a variable number of arguments to the end of it. */ + public static IntArrayDeque from(int... elements) { + final IntArrayDeque coll = new IntArrayDeque(elements.length); + coll.addLast(elements); + return coll; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/IntArrayList.java b/src/main/java/com/carrotsearch/hppc/IntArrayList.java new file mode 100755 index 00000000..6029be09 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntArrayList.java @@ -0,0 +1,586 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.IntPredicate; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; +import java.util.stream.IntStream; + +/** An array-backed list of ints. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java") +public class IntArrayList extends AbstractIntCollection + implements IntIndexedContainer, Preallocable, Cloneable, Accountable { + /** An immutable empty buffer (array). */ + public static final int[] EMPTY_ARRAY = new int[0]; + + ; + + /** Reuse the same strategy instance. */ + private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = + BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; + + /** + * Internal array for storing the list. The array may be larger than the current size ({@link + * #size()}). + */ + public int[] buffer = EMPTY_ARRAY; + + /** Current number of elements stored in {@link #buffer}. */ + public int elementsCount; + + /** Buffer resizing strategy. */ + protected final ArraySizingStrategy resizer; + + /** New instance with sane defaults. */ + public IntArrayList() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public IntArrayList(int expectedElements) { + this(expectedElements, DEFAULT_SIZING_STRATEGY); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public IntArrayList(int expectedElements, ArraySizingStrategy resizer) { + assert resizer != null; + this.resizer = resizer; + buffer = Arrays.copyOf(buffer, expectedElements); + } + + /** Creates a new list from the elements of another container in its iteration order. */ + public IntArrayList(IntContainer container) { + this(container.size()); + addAll(container); + } + + /** {@inheritDoc} */ + @Override + public void add(int e1) { + ensureBufferSpace(1); + buffer[elementsCount++] = e1; + } + + /** + * Appends two elements at the end of the list. To add more than two elements, use add + * (vararg-version) or access the buffer directly (tight loop). + */ + public void add(int e1, int e2) { + ensureBufferSpace(2); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + } + + /** Add all elements from a range of given array to the list. */ + public void add(int[] elements, int start, int length) { + assert length >= 0 : "Length must be >= 0"; + + ensureBufferSpace(length); + System.arraycopy(elements, start, buffer, elementsCount, length); + elementsCount += length; + } + + /** + * Vararg-signature method for adding elements at the end of the list. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + */ + public final void add(int... elements) { + add(elements, 0, elements.length); + } + + /** Adds all elements from another container. */ + public int addAll(IntContainer container) { + final int size = container.size(); + ensureBufferSpace(size); + + for (IntCursor cursor : container) { + add(cursor.value); + } + + return size; + } + + /** Adds all elements from another iterable. */ + public int addAll(Iterable iterable) { + int size = 0; + for (IntCursor cursor : iterable) { + add(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public void insert(int index, int e1) { + assert (index >= 0 && index <= size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + "]."; + + ensureBufferSpace(1); + System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index); + buffer[index] = e1; + elementsCount++; + } + + /** {@inheritDoc} */ + @Override + public int get(int index) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + return buffer[index]; + } + + /** {@inheritDoc} */ + @Override + public int set(int index, int e1) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + final int v = buffer[index]; + buffer[index] = e1; + return v; + } + + /** {@inheritDoc} */ + @Override + public int removeAt(int index) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + final int v = buffer[index]; + System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index); + + return v; + } + + /** {@inheritDoc} */ + @Override + public int removeLast() { + assert elementsCount > 0; + + final int v = buffer[--elementsCount]; + + return v; + } + + /** {@inheritDoc} */ + @Override + public void removeRange(int fromIndex, int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex); + final int count = toIndex - fromIndex; + elementsCount -= count; + } + + /** {@inheritDoc} */ + @Override + public boolean removeElement(int e1) { + return removeFirst(e1) != -1; + } + + /** {@inheritDoc} */ + @Override + public int removeFirst(int e1) { + final int index = indexOf(e1); + if (index >= 0) removeAt(index); + return index; + } + + /** {@inheritDoc} */ + @Override + public int removeLast(int e1) { + final int index = lastIndexOf(e1); + if (index >= 0) removeAt(index); + return index; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(int e1) { + int to = 0; + for (int from = 0; from < elementsCount; from++) { + if (((e1) == (buffer[from]))) { + continue; + } + if (to != from) { + buffer[to] = buffer[from]; + } + to++; + } + final int deleted = elementsCount - to; + this.elementsCount = to; + + return deleted; + } + + /** {@inheritDoc} */ + @Override + public boolean contains(int e1) { + return indexOf(e1) >= 0; + } + + /** {@inheritDoc} */ + @Override + public int indexOf(int e1) { + for (int i = 0; i < elementsCount; i++) { + if (((e1) == (buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int lastIndexOf(int e1) { + for (int i = elementsCount - 1; i >= 0; i--) { + if (((e1) == (buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return elementsCount == 0; + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + final int bufferLen = (buffer == null ? 0 : buffer.length); + if (expectedElements > bufferLen) { + ensureBufferSpace(expectedElements - size()); + } + } + + /** + * Ensures the internal buffer has enough free slots to store expectedAdditions. + * Increases internal buffer size if needed. + */ + protected void ensureBufferSpace(int expectedAdditions) { + final int bufferLen = (buffer == null ? 0 : buffer.length); + if (elementsCount + expectedAdditions > bufferLen) { + final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions); + assert newSize >= elementsCount + expectedAdditions + : "Resizer failed to" + + " return sensible new size: " + + newSize + + " <= " + + (elementsCount + expectedAdditions); + + this.buffer = Arrays.copyOf(buffer, newSize); + } + } + + /** + * Truncate or expand the list to the new size. If the list is truncated, the buffer will not be + * reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated + * values will be reset to the default value (zero). If the list is expanded, the elements beyond + * the current size are initialized with JVM-defaults (zero or null values). + */ + public void resize(int newSize) { + if (newSize <= buffer.length) { + if (newSize < elementsCount) { + Arrays.fill(buffer, newSize, elementsCount, 0); + } else { + Arrays.fill(buffer, elementsCount, newSize, 0); + } + } else { + ensureCapacity(newSize); + } + this.elementsCount = newSize; + } + + /** {@inheritDoc} */ + @Override + public int size() { + return elementsCount; + } + + /** Trim the internal buffer to the current size. */ + public void trimToSize() { + if (size() != this.buffer.length) { + this.buffer = toArray(); + } + } + + /** + * Sets the number of stored elements to zero. Releases and initializes the internal storage array + * to default values. To clear the list without cleaning the buffer, simply set the {@link + * #elementsCount} field to zero. + */ + @Override + public void clear() { + Arrays.fill(buffer, 0, elementsCount, 0); + this.elementsCount = 0; + } + + /** Sets the number of stored elements to zero and releases the internal storage array. */ + @Override + public void release() { + this.buffer = EMPTY_ARRAY; + this.elementsCount = 0; + } + + /** + * {@inheritDoc} + * + *

The returned array is sized to match exactly the number of elements of the stack. + */ + @Override + public int[] toArray() { + + return Arrays.copyOf(buffer, elementsCount); + } + + @Override + public IntStream stream() { + + return Arrays.stream(buffer, 0, size()); + } + + /** {@inheritDoc} */ + @Override + public IntIndexedContainer sort() { + Arrays.sort(buffer, 0, elementsCount); + return this; + } + + /** {@inheritDoc} */ + @Override + public IntIndexedContainer reverse() { + for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) { + int tmp = buffer[i]; + buffer[i] = buffer[j]; + buffer[j] = tmp; + } + return this; + } + + /** + * Clone this object. The returned clone will reuse the same hash function and array resizing + * strategy. + */ + @Override + public IntArrayList clone() { + try { + + final IntArrayList cloned = (IntArrayList) super.clone(); + cloned.buffer = buffer.clone(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 1, max = elementsCount; + for (int i = 0; i < max; i++) { + h = 31 * h + BitMixer.mix(this.buffer[i]); + } + return h; + } + + /** + * Returns true only if the other object is an instance of the same class and with + * the same elements. + */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Compare index-aligned elements against another {@link IntIndexedContainer}. */ + protected boolean equalElements(IntArrayList other) { + int max = size(); + if (other.size() != max) { + return false; + } + + for (int i = 0; i < max; i++) { + if (!((get(i)) == (other.get(i)))) { + return false; + } + } + + return true; + } + + @Override + public long ramBytesAllocated() { + // int: elementsCount + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES + + resizer.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(buffer); + } + + @Override + public long ramBytesUsed() { + // int: elementsCount + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES + + resizer.ramBytesUsed() + + RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount); + } + + /** An iterator implementation for {@link IntArrayList#iterator}. */ + static final class ValueIterator extends AbstractIterator { + private final IntCursor cursor; + + private final int[] buffer; + private final int size; + + public ValueIterator(int[] buffer, int size) { + this.cursor = new IntCursor(); + this.cursor.index = -1; + this.size = size; + this.buffer = buffer; + } + + @Override + protected IntCursor fetch() { + if (cursor.index + 1 == size) return done(); + + cursor.value = buffer[++cursor.index]; + return cursor; + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new ValueIterator(buffer, size()); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + return forEach(procedure, 0, size()); + } + + /** + * Applies procedure to a slice of the list, fromIndex, inclusive, to + * toIndex, exclusive. + */ + public T forEach(T procedure, int fromIndex, final int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + final int[] buffer = this.buffer; + for (int i = fromIndex; i < toIndex; i++) { + procedure.apply(buffer[i]); + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntPredicate predicate) { + final int[] buffer = this.buffer; + final int elementsCount = this.elementsCount; + int to = 0; + int from = 0; + try { + for (; from < elementsCount; from++) { + if (predicate.apply(buffer[from])) { + buffer[from] = 0; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0; + } + to++; + } + } finally { + // Keep the list in a consistent state, even if the predicate throws an exception. + for (; from < elementsCount; from++) { + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0; + } + to++; + } + + this.elementsCount = to; + } + + return elementsCount - to; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + return forEach(predicate, 0, size()); + } + + /** + * Applies predicate to a slice of the list, fromIndex, inclusive, to + * toIndex, exclusive, or until predicate returns false. + */ + public T forEach(T predicate, int fromIndex, final int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + final int[] buffer = this.buffer; + for (int i = fromIndex; i < toIndex; i++) { + if (!predicate.apply(buffer[i])) break; + } + + return predicate; + } + + /** + * Create a list from a variable number of arguments or an array of int. The elements + * are copied from the argument to the internal buffer. + */ + public static IntArrayList from(int... elements) { + final IntArrayList list = new IntArrayList(elements.length); + list.add(elements); + return list; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/IntBufferVisualizer.java b/src/main/java/com/carrotsearch/hppc/IntBufferVisualizer.java new file mode 100755 index 00000000..dddbbfc3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntBufferVisualizer.java @@ -0,0 +1,33 @@ +package com.carrotsearch.hppc; + +/** + * Reused buffer visualization routines. + * + * @see IntSet#visualizeKeyDistribution(int) + * @see IntVTypeMap#visualizeKeyDistribution(int) + */ +class IntBufferVisualizer { + static String visualizeKeyDistribution(int[] buffer, int max, int characters) { + final StringBuilder b = new StringBuilder(); + final char[] chars = ".123456789X".toCharArray(); + for (int i = 1, start = -1; i <= characters; i++) { + int end = (int) ((long) i * max / characters); + + if (start + 1 <= end) { + int taken = 0; + int slots = 0; + for (int slot = start + 1; slot <= end; slot++, slots++) { + if (!((buffer[slot]) == 0)) { + taken++; + } + } + b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]); + start = end; + } + } + while (b.length() < characters) { + b.append(' '); + } + return b.toString(); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/IntByteAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/IntByteAssociativeContainer.java new file mode 100755 index 00000000..474cc041 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntByteAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see IntContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface IntByteAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(int key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntBytePredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link IntByteProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link IntBytePredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public IntCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public ByteContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntByteHashMap.java b/src/main/java/com/carrotsearch/hppc/IntByteHashMap.java new file mode 100755 index 00000000..2e69d807 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntByteHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of int to byte, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeHashMap.java") +public class IntByteHashMap implements IntByteMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public int[] keys; + + /** The array holding values. */ + public byte[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public IntByteHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public IntByteHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public IntByteHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public IntByteHashMap(IntByteAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public byte put(int key, byte value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + byte previousValue = hasEmptyKey ? values[mask + 1] : ((byte) 0); + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final byte previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return ((byte) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(IntByteAssociativeContainer container) { + final int count = size(); + for (IntByteCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (IntByteCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public byte putOrAdd(int key, byte putValue, byte incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((byte) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public byte addTo(int key, byte incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public byte remove(int key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return ((byte) 0); + } + hasEmptyKey = false; + byte previousValue = values[mask + 1]; + values[mask + 1] = ((byte) 0); + return previousValue; + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final byte previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return ((byte) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof IntLookupContainer) { + if (hasEmptyKey && other.contains(0)) { + hasEmptyKey = false; + values[mask + 1] = ((byte) 0); + } + + final int[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + int existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (IntCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntBytePredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(0, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = ((byte) 0); + } + } + + final int[] keys = this.keys; + final byte[] values = this.values; + for (int slot = 0; slot <= mask; ) { + int existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(0)) { + hasEmptyKey = false; + values[mask + 1] = ((byte) 0); + } + } + + final int[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + int existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public byte get(int key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : ((byte) 0); + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return ((byte) 0); + } + } + + /** {@inheritDoc} */ + @Override + public byte getOrDefault(int key, byte defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(int key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(int key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public byte indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public byte indexReplace(int index, byte newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + byte previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, int key, byte value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public byte indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + byte previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = ((byte) 0); + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, 0); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (IntByteCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(IntByteHashMap other) { + if (other.size() != size()) { + return false; + } + + for (IntByteCursor c : other) { + int key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final int[] prevKeys = this.keys; + final byte[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final IntByteCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new IntByteCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntByteCursor fetch() { + final int mask = IntByteHashMap.this.mask; + while (index <= mask) { + int existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = 0; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final int[] keys = this.keys; + final byte[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(0, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final int[] keys = this.keys; + final byte[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(0, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { + private final IntByteHashMap owner = IntByteHashMap.this; + + @Override + public boolean contains(int e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((IntByteProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((IntBytePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(IntPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final int e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final IntCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new IntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntCursor fetch() { + final int mask = IntByteHashMap.this.mask; + while (index <= mask) { + int existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = 0; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public ByteCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractByteCollection { + private final IntByteHashMap owner = IntByteHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(byte value) { + for (IntByteCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (IntByteCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (IntByteCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final byte e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final BytePredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ByteCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new ByteCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ByteCursor fetch() { + final int mask = IntByteHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public IntByteHashMap clone() { + try { + + IntByteHashMap cloned = (IntByteHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (IntByteCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return IntBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static IntByteHashMap from(int[] keys, byte[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + IntByteHashMap map = new IntByteHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(int key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(int[] fromKeys, byte[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final int[] keys = this.keys; + final byte[] values = this.values; + final int mask = this.mask; + int existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + int[] prevKeys = this.keys; + byte[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new int[arraySize + emptyElementSlot]); + this.values = (new byte[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, int pendingKey, byte pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final int[] prevKeys = this.keys; + final byte[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final int[] keys = this.keys; + final byte[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final int existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = 0; + values[gapSlot] = ((byte) 0); + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/IntByteMap.java b/src/main/java/com/carrotsearch/hppc/IntByteMap.java new file mode 100755 index 00000000..06ce8aa8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntByteMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.IntByteCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface IntByteMap extends IntByteAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public byte get(int key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public byte getOrDefault(int key, byte defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public byte put(int key, byte value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(int key, byte value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(IntByteAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public byte putOrAdd(int key, byte putValue, byte incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public byte addTo(int key, byte additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public byte remove(int key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link IntByteMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(int key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public byte indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public byte indexReplace(int index, byte newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, int key, byte value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public byte indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntCharAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/IntCharAssociativeContainer.java new file mode 100755 index 00000000..adf2f6b1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntCharAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see IntContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface IntCharAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(int key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntCharPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link IntCharProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link IntCharPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public IntCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public CharContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntCharHashMap.java b/src/main/java/com/carrotsearch/hppc/IntCharHashMap.java new file mode 100755 index 00000000..f3bc23a9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntCharHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of int to char, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeHashMap.java") +public class IntCharHashMap implements IntCharMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public int[] keys; + + /** The array holding values. */ + public char[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public IntCharHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public IntCharHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public IntCharHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public IntCharHashMap(IntCharAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public char put(int key, char value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + char previousValue = hasEmptyKey ? values[mask + 1] : ((char) 0); + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final char previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return ((char) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(IntCharAssociativeContainer container) { + final int count = size(); + for (IntCharCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (IntCharCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public char putOrAdd(int key, char putValue, char incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((char) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public char addTo(int key, char incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public char remove(int key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return ((char) 0); + } + hasEmptyKey = false; + char previousValue = values[mask + 1]; + values[mask + 1] = ((char) 0); + return previousValue; + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final char previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return ((char) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof IntLookupContainer) { + if (hasEmptyKey && other.contains(0)) { + hasEmptyKey = false; + values[mask + 1] = ((char) 0); + } + + final int[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + int existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (IntCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntCharPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(0, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = ((char) 0); + } + } + + final int[] keys = this.keys; + final char[] values = this.values; + for (int slot = 0; slot <= mask; ) { + int existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(0)) { + hasEmptyKey = false; + values[mask + 1] = ((char) 0); + } + } + + final int[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + int existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public char get(int key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : ((char) 0); + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return ((char) 0); + } + } + + /** {@inheritDoc} */ + @Override + public char getOrDefault(int key, char defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(int key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(int key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public char indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public char indexReplace(int index, char newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + char previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, int key, char value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public char indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + char previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = ((char) 0); + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, 0); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (IntCharCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(IntCharHashMap other) { + if (other.size() != size()) { + return false; + } + + for (IntCharCursor c : other) { + int key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final int[] prevKeys = this.keys; + final char[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final IntCharCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new IntCharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntCharCursor fetch() { + final int mask = IntCharHashMap.this.mask; + while (index <= mask) { + int existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = 0; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final int[] keys = this.keys; + final char[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(0, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final int[] keys = this.keys; + final char[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(0, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { + private final IntCharHashMap owner = IntCharHashMap.this; + + @Override + public boolean contains(int e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((IntCharProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((IntCharPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(IntPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final int e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final IntCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new IntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntCursor fetch() { + final int mask = IntCharHashMap.this.mask; + while (index <= mask) { + int existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = 0; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public CharCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractCharCollection { + private final IntCharHashMap owner = IntCharHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(char value) { + for (IntCharCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (IntCharCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (IntCharCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final char e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final CharPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final CharCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new CharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharCursor fetch() { + final int mask = IntCharHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public IntCharHashMap clone() { + try { + + IntCharHashMap cloned = (IntCharHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (IntCharCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return IntBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static IntCharHashMap from(int[] keys, char[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + IntCharHashMap map = new IntCharHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(int key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(int[] fromKeys, char[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final int[] keys = this.keys; + final char[] values = this.values; + final int mask = this.mask; + int existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + int[] prevKeys = this.keys; + char[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new int[arraySize + emptyElementSlot]); + this.values = (new char[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, int pendingKey, char pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final int[] prevKeys = this.keys; + final char[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final int[] keys = this.keys; + final char[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final int existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = 0; + values[gapSlot] = ((char) 0); + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/IntCharMap.java b/src/main/java/com/carrotsearch/hppc/IntCharMap.java new file mode 100755 index 00000000..dd06fe44 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntCharMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.IntCharCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface IntCharMap extends IntCharAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public char get(int key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public char getOrDefault(int key, char defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public char put(int key, char value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(int key, char value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(IntCharAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public char putOrAdd(int key, char putValue, char incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public char addTo(int key, char additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public char remove(int key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link IntCharMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(int key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public char indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public char indexReplace(int index, char newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, int key, char value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public char indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntCollection.java b/src/main/java/com/carrotsearch/hppc/IntCollection.java new file mode 100755 index 00000000..16ae39bf --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntCollection.java @@ -0,0 +1,64 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.predicates.IntPredicate; + +/** + * A collection allows basic, efficient operations on sets of elements (difference and + * intersection). + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java") +public interface IntCollection extends IntContainer { + /** + * Removes all occurrences of e from this collection. + * + * @param e Element to be removed from this collection, if present. + * @return The number of removed elements as a result of this call. + */ + public int removeAll(int e); + + /** + * Removes all elements in this collection that are present in c. + * + * @return Returns the number of removed elements. + */ + public int removeAll(IntLookupContainer c); + + /** + * Removes all elements in this collection for which the given predicate returns true + * . + * + * @return Returns the number of removed elements. + */ + public int removeAll(IntPredicate predicate); + + /** + * Keeps all elements in this collection that are present in c. Runs in time + * proportional to the number of elements in this collection. Equivalent of sets intersection. + * + * @return Returns the number of removed elements. + */ + public int retainAll(IntLookupContainer c); + + /** + * Keeps all elements in this collection for which the given predicate returns true. + * + * @return Returns the number of removed elements. + */ + public int retainAll(IntPredicate predicate); + + /** + * Removes all elements from this collection. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntContainer.java b/src/main/java/com/carrotsearch/hppc/IntContainer.java new file mode 100755 index 00000000..fd8c1b3a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntContainer.java @@ -0,0 +1,76 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.IntCursor; +import com.carrotsearch.hppc.predicates.IntPredicate; +import com.carrotsearch.hppc.procedures.IntProcedure; +import java.util.Iterator; + +/** A generic container holding ints. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java") +public interface IntContainer extends Iterable { + /** + * Returns an iterator to a cursor traversing the collection. The order of traversal is not + * defined. More than one cursor may be active at a time. The behavior of iterators is undefined + * if structural changes are made to the underlying collection. + * + *

The iterator is implemented as a cursor and it returns the same cursor instance on + * every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current + * list's value (or index in the list) use the cursor's public fields. An example is shown below. + * + *

+   * for (IntCursor<int> c : container) {
+   *   System.out.println("index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator iterator(); + + /** + * Lookup a given element in the container. This operation has no speed guarantees (may be linear + * with respect to the size of this container). + * + * @return Returns true if this container has an element equal to e. + */ + public boolean contains(int e); + + /** + * Return the current number of elements in this container. The time for calculating the + * container's size may take O(n) time, although implementing classes should try to + * maintain the current size and return in constant time. + */ + public int size(); + + /** Shortcut for size() == 0. */ + public boolean isEmpty(); + + /** + * Copies all elements of this container to an array. + * + *

The returned array is always a copy, regardless of the storage used by the container. + */ + public int[] toArray(); + + /** + * Applies a procedure to all container elements. Returns the argument (any subclass + * of {@link IntProcedure}. This lets the caller to call methods of the argument by chaining the + * call (even if the argument is an anonymous type) to retrieve computed values, for example + * (IntContainer): + * + *

+   * int count = container.forEach(new IntProcedure() {
+   *   int count; // this is a field declaration in an anonymous class.
+   *
+   *   public void apply(int value) {
+   *     count++;
+   *   }
+   * }).count;
+   * 
+ */ + public T forEach(T procedure); + + /** + * Applies a predicate to container elements as long, as the predicate returns + * true. The iteration is interrupted otherwise. + */ + public T forEach(T predicate); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntDeque.java b/src/main/java/com/carrotsearch/hppc/IntDeque.java new file mode 100755 index 00000000..e7981ad5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntDeque.java @@ -0,0 +1,77 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.IntCursor; +import com.carrotsearch.hppc.predicates.IntPredicate; +import com.carrotsearch.hppc.procedures.IntProcedure; +import java.util.Deque; +import java.util.Iterator; + +/** + * A linear collection that supports element insertion and removal at both ends. + * + * @see Deque + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java") +public interface IntDeque extends IntCollection { + /** + * Removes the first element that equals e. + * + * @return The deleted element's index or -1 if the element was not found. + */ + public int removeFirst(int e); + + /** + * Removes the last element that equals e. + * + * @return The deleted element's index or -1 if the element was not found. + */ + public int removeLast(int e); + + /** Inserts the specified element at the front of this deque. */ + public void addFirst(int e); + + /** Inserts the specified element at the end of this deque. */ + public void addLast(int e); + + /** + * Retrieves and removes the first element of this deque. + * + * @return the head (first) element of this deque. + */ + public int removeFirst(); + + /** + * Retrieves and removes the last element of this deque. + * + * @return the tail of this deque. + */ + public int removeLast(); + + /** + * Retrieves the first element of this deque but does not remove it. + * + * @return the head of this deque. + */ + public int getFirst(); + + /** + * Retrieves the last element of this deque but does not remove it. + * + * @return the head of this deque. + */ + public int getLast(); + + /** + * @return An iterator over elements in this deque in tail-to-head order. + */ + public Iterator descendingIterator(); + + /** Applies a procedure to all elements in tail-to-head order. */ + public T descendingForEach(T procedure); + + /** + * Applies a predicate to container elements as long, as the predicate returns + * true. The iteration is interrupted otherwise. + */ + public T descendingForEach(T predicate); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntDoubleAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/IntDoubleAssociativeContainer.java new file mode 100755 index 00000000..b447931f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntDoubleAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see IntContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface IntDoubleAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *
+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(int key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntDoublePredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link IntDoubleProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link IntDoublePredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public IntCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public DoubleContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/IntDoubleHashMap.java new file mode 100755 index 00000000..d070d0f8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntDoubleHashMap.java @@ -0,0 +1,1082 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of int to double, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeHashMap.java") +public class IntDoubleHashMap implements IntDoubleMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public int[] keys; + + /** The array holding values. */ + public double[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public IntDoubleHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public IntDoubleHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public IntDoubleHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public IntDoubleHashMap(IntDoubleAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public double put(int key, double value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + double previousValue = hasEmptyKey ? values[mask + 1] : 0d; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final double previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0d; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(IntDoubleAssociativeContainer container) { + final int count = size(); + for (IntDoubleCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (IntDoubleCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public double putOrAdd(int key, double putValue, double incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((double) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public double addTo(int key, double incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public double remove(int key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return 0d; + } + hasEmptyKey = false; + double previousValue = values[mask + 1]; + values[mask + 1] = 0d; + return previousValue; + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final double previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0d; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof IntLookupContainer) { + if (hasEmptyKey && other.contains(0)) { + hasEmptyKey = false; + values[mask + 1] = 0d; + } + + final int[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + int existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (IntCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntDoublePredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(0, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0d; + } + } + + final int[] keys = this.keys; + final double[] values = this.values; + for (int slot = 0; slot <= mask; ) { + int existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(0)) { + hasEmptyKey = false; + values[mask + 1] = 0d; + } + } + + final int[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + int existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public double get(int key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : 0d; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0d; + } + } + + /** {@inheritDoc} */ + @Override + public double getOrDefault(int key, double defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(int key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(int key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public double indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public double indexReplace(int index, double newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + double previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, int key, double value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public double indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + double previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0d; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, 0); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (IntDoubleCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(IntDoubleHashMap other) { + if (other.size() != size()) { + return false; + } + + for (IntDoubleCursor c : other) { + int key = c.key; + if (!containsKey(key) + || !(Double.doubleToLongBits(c.value) == Double.doubleToLongBits(get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final int[] prevKeys = this.keys; + final double[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final IntDoubleCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new IntDoubleCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntDoubleCursor fetch() { + final int mask = IntDoubleHashMap.this.mask; + while (index <= mask) { + int existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = 0; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final int[] keys = this.keys; + final double[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(0, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final int[] keys = this.keys; + final double[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(0, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { + private final IntDoubleHashMap owner = IntDoubleHashMap.this; + + @Override + public boolean contains(int e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((IntDoubleProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((IntDoublePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(IntPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final int e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final IntCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new IntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntCursor fetch() { + final int mask = IntDoubleHashMap.this.mask; + while (index <= mask) { + int existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = 0; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public DoubleCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractDoubleCollection { + private final IntDoubleHashMap owner = IntDoubleHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(double value) { + for (IntDoubleCursor c : owner) { + if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (IntDoubleCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (IntDoubleCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final double e) { + return owner.removeAll( + (key, value) -> (Double.doubleToLongBits(e) == Double.doubleToLongBits(value))); + } + + @Override + public int removeAll(final DoublePredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final DoubleCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new DoubleCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected DoubleCursor fetch() { + final int mask = IntDoubleHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public IntDoubleHashMap clone() { + try { + + IntDoubleHashMap cloned = (IntDoubleHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (IntDoubleCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return IntBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static IntDoubleHashMap from(int[] keys, double[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + IntDoubleHashMap map = new IntDoubleHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(int key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(int[] fromKeys, double[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final int[] keys = this.keys; + final double[] values = this.values; + final int mask = this.mask; + int existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + int[] prevKeys = this.keys; + double[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new int[arraySize + emptyElementSlot]); + this.values = (new double[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, int pendingKey, double pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final int[] prevKeys = this.keys; + final double[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final int[] keys = this.keys; + final double[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final int existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = 0; + values[gapSlot] = 0d; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/IntDoubleMap.java b/src/main/java/com/carrotsearch/hppc/IntDoubleMap.java new file mode 100755 index 00000000..03691ffa --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntDoubleMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.IntDoubleCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface IntDoubleMap extends IntDoubleAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public double get(int key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public double getOrDefault(int key, double defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public double put(int key, double value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(int key, double value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(IntDoubleAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public double putOrAdd(int key, double putValue, double incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public double addTo(int key, double additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public double remove(int key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link IntDoubleMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(int key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public double indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public double indexReplace(int index, double newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, int key, double value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public double indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntFloatAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/IntFloatAssociativeContainer.java new file mode 100755 index 00000000..50a4b963 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntFloatAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see IntContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface IntFloatAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(int key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntFloatPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link IntFloatProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link IntFloatPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public IntCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public FloatContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/IntFloatHashMap.java new file mode 100755 index 00000000..f7a3a4f5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntFloatHashMap.java @@ -0,0 +1,1081 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of int to float, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeHashMap.java") +public class IntFloatHashMap implements IntFloatMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public int[] keys; + + /** The array holding values. */ + public float[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public IntFloatHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public IntFloatHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public IntFloatHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public IntFloatHashMap(IntFloatAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public float put(int key, float value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + float previousValue = hasEmptyKey ? values[mask + 1] : 0f; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final float previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0f; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(IntFloatAssociativeContainer container) { + final int count = size(); + for (IntFloatCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (IntFloatCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public float putOrAdd(int key, float putValue, float incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((float) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public float addTo(int key, float incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public float remove(int key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return 0f; + } + hasEmptyKey = false; + float previousValue = values[mask + 1]; + values[mask + 1] = 0f; + return previousValue; + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final float previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0f; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof IntLookupContainer) { + if (hasEmptyKey && other.contains(0)) { + hasEmptyKey = false; + values[mask + 1] = 0f; + } + + final int[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + int existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (IntCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntFloatPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(0, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0f; + } + } + + final int[] keys = this.keys; + final float[] values = this.values; + for (int slot = 0; slot <= mask; ) { + int existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(0)) { + hasEmptyKey = false; + values[mask + 1] = 0f; + } + } + + final int[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + int existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public float get(int key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : 0f; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0f; + } + } + + /** {@inheritDoc} */ + @Override + public float getOrDefault(int key, float defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(int key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(int key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public float indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public float indexReplace(int index, float newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + float previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, int key, float value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public float indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + float previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0f; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, 0); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (IntFloatCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(IntFloatHashMap other) { + if (other.size() != size()) { + return false; + } + + for (IntFloatCursor c : other) { + int key = c.key; + if (!containsKey(key) || !(Float.floatToIntBits(c.value) == Float.floatToIntBits(get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final int[] prevKeys = this.keys; + final float[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final IntFloatCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new IntFloatCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntFloatCursor fetch() { + final int mask = IntFloatHashMap.this.mask; + while (index <= mask) { + int existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = 0; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final int[] keys = this.keys; + final float[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(0, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final int[] keys = this.keys; + final float[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(0, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { + private final IntFloatHashMap owner = IntFloatHashMap.this; + + @Override + public boolean contains(int e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((IntFloatProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((IntFloatPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(IntPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final int e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final IntCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new IntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntCursor fetch() { + final int mask = IntFloatHashMap.this.mask; + while (index <= mask) { + int existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = 0; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public FloatCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractFloatCollection { + private final IntFloatHashMap owner = IntFloatHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(float value) { + for (IntFloatCursor c : owner) { + if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (IntFloatCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (IntFloatCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final float e) { + return owner.removeAll( + (key, value) -> (Float.floatToIntBits(e) == Float.floatToIntBits(value))); + } + + @Override + public int removeAll(final FloatPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final FloatCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new FloatCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected FloatCursor fetch() { + final int mask = IntFloatHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public IntFloatHashMap clone() { + try { + + IntFloatHashMap cloned = (IntFloatHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (IntFloatCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return IntBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static IntFloatHashMap from(int[] keys, float[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + IntFloatHashMap map = new IntFloatHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(int key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(int[] fromKeys, float[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final int[] keys = this.keys; + final float[] values = this.values; + final int mask = this.mask; + int existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + int[] prevKeys = this.keys; + float[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new int[arraySize + emptyElementSlot]); + this.values = (new float[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, int pendingKey, float pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final int[] prevKeys = this.keys; + final float[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final int[] keys = this.keys; + final float[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final int existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = 0; + values[gapSlot] = 0f; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/IntFloatMap.java b/src/main/java/com/carrotsearch/hppc/IntFloatMap.java new file mode 100755 index 00000000..4a1e2c9b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntFloatMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.IntFloatCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface IntFloatMap extends IntFloatAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public float get(int key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public float getOrDefault(int key, float defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public float put(int key, float value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(int key, float value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(IntFloatAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public float putOrAdd(int key, float putValue, float incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public float addTo(int key, float additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public float remove(int key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link IntFloatMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(int key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public float indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public float indexReplace(int index, float newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, int key, float value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public float indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntHashSet.java b/src/main/java/com/carrotsearch/hppc/IntHashSet.java new file mode 100755 index 00000000..f6aae01d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntHashSet.java @@ -0,0 +1,787 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash set of ints, implemented using open addressing with linear probing for + * collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeHashSet.java") +public class IntHashSet extends AbstractIntCollection + implements IntLookupContainer, IntSet, Preallocable, Cloneable, Accountable { + /** The hash array holding keys. */ + public int[] keys; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any. + * + * @see #size() + * @see #hasEmptyKey + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** + * New instance with sane defaults. + * + * @see #IntHashSet(int, double) + */ + public IntHashSet() { + this(DEFAULT_EXPECTED_ELEMENTS, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with sane defaults. + * + * @see #IntHashSet(int, double) + */ + public IntHashSet(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public IntHashSet(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** New instance copying elements from another {@link IntContainer}. */ + public IntHashSet(IntContainer container) { + this(container.size()); + addAll(container); + } + + /** {@inheritDoc} */ + @Override + public boolean add(int key) { + if (((key) == 0)) { + assert ((keys[mask + 1]) == 0); + boolean added = !hasEmptyKey; + hasEmptyKey = true; + return added; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return false; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key); + } else { + keys[slot] = key; + } + + assigned++; + return true; + } + } + + /** + * Adds all elements from the given list (vararg) to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + */ + public final int addAll(int... elements) { + ensureCapacity(elements.length); + int count = 0; + for (int e : elements) { + if (add(e)) { + count++; + } + } + return count; + } + + /** + * Adds all elements from the given {@link IntContainer} to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + */ + public int addAll(IntContainer container) { + ensureCapacity(container.size()); + return addAll((Iterable) container); + } + + /** + * Adds all elements from the given iterable to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + */ + public int addAll(Iterable iterable) { + int count = 0; + for (IntCursor cursor : iterable) { + if (add(cursor.value)) { + count++; + } + } + return count; + } + + /** {@inheritDoc} */ + @Override + public int[] toArray() { + + final int[] cloned = (new int[size()]); + int j = 0; + if (hasEmptyKey) { + cloned[j++] = 0; + } + + final int[] keys = this.keys; + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + int existing; + if (!((existing = keys[slot]) == 0)) { + cloned[j++] = existing; + } + } + + return cloned; + } + + /** An alias for the (preferred) {@link #removeAll}. */ + public boolean remove(int key) { + if (((key) == 0)) { + boolean hadEmptyKey = hasEmptyKey; + hasEmptyKey = false; + return hadEmptyKey; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + shiftConflictingKeys(slot); + return true; + } + slot = (slot + 1) & mask; + } + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(int key) { + return remove(key) ? 1 : 0; + } + + /** + * Removes all keys present in a given container. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntContainer other) { + final int before = size(); + + // Try to iterate over the smaller set or over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof IntLookupContainer) { + if (hasEmptyKey && other.contains(0)) { + hasEmptyKey = false; + } + + final int[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + int existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (IntCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntPredicate predicate) { + int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(0)) { + hasEmptyKey = false; + } + } + + final int[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + int existing; + if (!((existing = keys[slot]) == 0)) { + if (predicate.apply(existing)) { + shiftConflictingKeys(slot); + continue; // Repeat the check for the same slot i (shifted). + } + } + slot++; + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public boolean contains(int key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + return false; + } + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + Arrays.fill(keys, 0); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + keys = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return size() == 0; + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final int[] prevKeys = this.keys; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys); + } + } + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + final int[] keys = this.keys; + for (int slot = mask; slot >= 0; slot--) { + int existing; + if (!((existing = keys[slot]) == 0)) { + h += BitMixer.mix(existing); + } + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && sameKeys(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + private boolean sameKeys(IntSet other) { + if (other.size() != size()) { + return false; + } + + for (IntCursor c : other) { + if (!contains(c.value)) { + return false; + } + } + + return true; + } + + /** {@inheritDoc} */ + @Override + public IntHashSet clone() { + try { + + IntHashSet cloned = (IntHashSet) super.clone(); + cloned.keys = keys.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + @Override + public long ramBytesAllocated() { + // int: assigned, mask, keyMixer, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys); + } + + @Override + public long ramBytesUsed() { + // int: assigned, mask, keyMixer, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + protected final class EntryIterator extends AbstractIterator { + private final IntCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new IntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntCursor fetch() { + final int mask = IntHashSet.this.mask; + while (index <= mask) { + int existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = 0; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + if (hasEmptyKey) { + procedure.apply(0); + } + + final int[] keys = this.keys; + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + int existing; + if (!((existing = keys[slot]) == 0)) { + procedure.apply(existing); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + if (hasEmptyKey) { + if (!predicate.apply(0)) { + return predicate; + } + } + + final int[] keys = this.keys; + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + int existing; + if (!((existing = keys[slot]) == 0)) { + if (!predicate.apply(existing)) { + break; + } + } + } + + return predicate; + } + + /** + * Create a set from a variable number of arguments or an array of int. The elements + * are copied from the argument to the internal buffer. + */ + public static IntHashSet from(int... elements) { + final IntHashSet set = new IntHashSet(elements.length); + set.addAll(elements); + return set; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(int key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up logic in + * certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between modifications (it will not be affected by read-only + * operations). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the set. + * @return A non-negative value of the logical "index" of the key in the set or a negative value + * if the key did not exist. + */ + public int indexOf(int key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index) { + assert index < 0 || index <= mask || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** + * Returns the exact value of the existing key. This method makes sense for sets of objects which + * define custom key-equality relationship. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the equivalent key currently stored in the set. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public int indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return keys[index]; + } + + /** + * Replaces the existing equivalent key with the given one and returns any previous value stored + * for that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @param equivalentKey The key to put in the set as a replacement. Must be equivalent to the key + * currently stored at the provided index. + * @return Returns the previous key stored in the set. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public int indexReplace(int index, int equivalentKey) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + assert ((keys[index]) == (equivalentKey)); + + int previousValue = keys[index]; + keys[index] = equivalentKey; + return previousValue; + } + + /** + * Inserts a key for an index that is not present in the set. This method may help in avoiding + * double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public void indexInsert(int index, int key) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + assert ((keys[index]) == 0); + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key); + } else { + keys[index] = key; + } + + assigned++; + } + } + + /** + * Removes a key at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public void indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + if (index > mask) { + hasEmptyKey = false; + } else { + shiftConflictingKeys(index); + } + } + + @Override + public String visualizeKeyDistribution(int characters) { + return IntBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(int[] fromKeys) { + assert HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored keys into the new buffers. + final int[] keys = this.keys; + final int mask = this.mask; + int existing; + for (int i = fromKeys.length - 1; --i >= 0; ) { + if (!((existing = fromKeys[i]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + int[] prevKeys = this.keys; + try { + int emptyElementSlot = 1; + this.keys = (new int[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.keys == null ? 0 : size(), arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key to be inserted into the buffer but there is not + * enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, int pendingKey) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final int[] prevKeys = this.keys; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + + // Rehash old keys, including the pending key. + rehash(prevKeys); + } + + /** Shift all the slot-conflicting keys allocated to (and including) slot. */ + protected void shiftConflictingKeys(int gapSlot) { + final int[] keys = this.keys; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final int existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = 0; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/IntIndexedContainer.java b/src/main/java/com/carrotsearch/hppc/IntIndexedContainer.java new file mode 100755 index 00000000..0eb076ea --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntIndexedContainer.java @@ -0,0 +1,93 @@ +package com.carrotsearch.hppc; + +import java.util.RandomAccess; +import java.util.stream.IntStream; + +/** + * An indexed container provides random access to elements based on an index. Indexes + * are zero-based. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeIndexedContainer.java") +public interface IntIndexedContainer extends IntCollection, RandomAccess { + /** + * Removes the first element that equals e1, returning whether an element has been + * removed. + */ + public boolean removeElement(int e1); + + /** + * Removes the first element that equals e1, returning its deleted position or + * -1 if the element was not found. + */ + public int removeFirst(int e1); + + /** + * Removes the last element that equals e1, returning its deleted position or + * -1 if the element was not found. + */ + public int removeLast(int e1); + + /** + * Returns the index of the first occurrence of the specified element in this list, or -1 if this + * list does not contain the element. + */ + public int indexOf(int e1); + + /** + * Returns the index of the last occurrence of the specified element in this list, or -1 if this + * list does not contain the element. + */ + public int lastIndexOf(int e1); + + /** Adds an element to the end of this container (the last index is incremented by one). */ + public void add(int e1); + + /** + * Inserts the specified element at the specified position in this list. + * + * @param index The index at which the element should be inserted, shifting any existing and + * subsequent elements to the right. + */ + public void insert(int index, int e1); + + /** + * Replaces the element at the specified position in this list with the specified element. + * + * @return Returns the previous value in the list. + */ + public int set(int index, int e1); + + /** + * @return Returns the element at index index from the list. + */ + public int get(int index); + + /** + * Removes the element at the specified position in this container and returns it. + * + * @see #removeFirst + * @see #removeLast + * @see #removeAll + */ + public int removeAt(int index); + + /** Removes and returns the last element of this container. This container must not be empty. */ + public int removeLast(); + + /** + * Removes from this container all of the elements with indexes between fromIndex, + * inclusive, and toIndex, exclusive. + */ + public void removeRange(int fromIndex, int toIndex); + + /** Returns this container elements as a stream. */ + public IntStream stream(); + + /** Sorts the elements in this container and returns this container. */ + public IntIndexedContainer sort(); + + /** Reverses the elements in this container and returns this container. */ + public IntIndexedContainer reverse(); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntIntAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/IntIntAssociativeContainer.java new file mode 100755 index 00000000..fdb8772a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntIntAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see IntContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface IntIntAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(int key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntIntPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link IntIntProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link IntIntPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public IntCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public IntContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntIntHashMap.java b/src/main/java/com/carrotsearch/hppc/IntIntHashMap.java new file mode 100755 index 00000000..5380245c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntIntHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of int to int, implemented using open addressing with linear + * probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeHashMap.java") +public class IntIntHashMap implements IntIntMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public int[] keys; + + /** The array holding values. */ + public int[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public IntIntHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public IntIntHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public IntIntHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public IntIntHashMap(IntIntAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public int put(int key, int value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + int previousValue = hasEmptyKey ? values[mask + 1] : 0; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final int previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(IntIntAssociativeContainer container) { + final int count = size(); + for (IntIntCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (IntIntCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public int putOrAdd(int key, int putValue, int incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((int) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public int addTo(int key, int incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public int remove(int key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return 0; + } + hasEmptyKey = false; + int previousValue = values[mask + 1]; + values[mask + 1] = 0; + return previousValue; + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final int previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof IntLookupContainer) { + if (hasEmptyKey && other.contains(0)) { + hasEmptyKey = false; + values[mask + 1] = 0; + } + + final int[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + int existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (IntCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntIntPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(0, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0; + } + } + + final int[] keys = this.keys; + final int[] values = this.values; + for (int slot = 0; slot <= mask; ) { + int existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(0)) { + hasEmptyKey = false; + values[mask + 1] = 0; + } + } + + final int[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + int existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int get(int key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : 0; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0; + } + } + + /** {@inheritDoc} */ + @Override + public int getOrDefault(int key, int defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(int key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(int key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public int indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public int indexReplace(int index, int newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + int previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, int key, int value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public int indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + int previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, 0); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (IntIntCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(IntIntHashMap other) { + if (other.size() != size()) { + return false; + } + + for (IntIntCursor c : other) { + int key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final int[] prevKeys = this.keys; + final int[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final IntIntCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new IntIntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntIntCursor fetch() { + final int mask = IntIntHashMap.this.mask; + while (index <= mask) { + int existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = 0; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final int[] keys = this.keys; + final int[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(0, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final int[] keys = this.keys; + final int[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(0, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { + private final IntIntHashMap owner = IntIntHashMap.this; + + @Override + public boolean contains(int e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((IntIntProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((IntIntPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(IntPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final int e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final IntCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new IntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntCursor fetch() { + final int mask = IntIntHashMap.this.mask; + while (index <= mask) { + int existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = 0; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public IntCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractIntCollection { + private final IntIntHashMap owner = IntIntHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(int value) { + for (IntIntCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (IntIntCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (IntIntCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final int e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final IntPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final IntCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new IntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntCursor fetch() { + final int mask = IntIntHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public IntIntHashMap clone() { + try { + + IntIntHashMap cloned = (IntIntHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (IntIntCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return IntBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static IntIntHashMap from(int[] keys, int[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + IntIntHashMap map = new IntIntHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(int key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(int[] fromKeys, int[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final int[] keys = this.keys; + final int[] values = this.values; + final int mask = this.mask; + int existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + int[] prevKeys = this.keys; + int[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new int[arraySize + emptyElementSlot]); + this.values = (new int[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, int pendingKey, int pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final int[] prevKeys = this.keys; + final int[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final int[] keys = this.keys; + final int[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final int existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = 0; + values[gapSlot] = 0; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/IntIntMap.java b/src/main/java/com/carrotsearch/hppc/IntIntMap.java new file mode 100755 index 00000000..29097ecf --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntIntMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.IntIntCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface IntIntMap extends IntIntAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public int get(int key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public int getOrDefault(int key, int defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public int put(int key, int value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(int key, int value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(IntIntAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public int putOrAdd(int key, int putValue, int incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public int addTo(int key, int additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public int remove(int key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link IntIntMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(int key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public int indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public int indexReplace(int index, int newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, int key, int value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public int indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntLongAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/IntLongAssociativeContainer.java new file mode 100755 index 00000000..37f3887c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntLongAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see IntContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface IntLongAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(int key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntLongPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link IntLongProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link IntLongPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public IntCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public LongContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntLongHashMap.java b/src/main/java/com/carrotsearch/hppc/IntLongHashMap.java new file mode 100755 index 00000000..8a595142 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntLongHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of int to long, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeHashMap.java") +public class IntLongHashMap implements IntLongMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public int[] keys; + + /** The array holding values. */ + public long[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public IntLongHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public IntLongHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public IntLongHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public IntLongHashMap(IntLongAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public long put(int key, long value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + long previousValue = hasEmptyKey ? values[mask + 1] : 0L; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final long previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0L; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(IntLongAssociativeContainer container) { + final int count = size(); + for (IntLongCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (IntLongCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public long putOrAdd(int key, long putValue, long incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((long) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public long addTo(int key, long incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public long remove(int key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return 0L; + } + hasEmptyKey = false; + long previousValue = values[mask + 1]; + values[mask + 1] = 0L; + return previousValue; + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final long previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0L; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof IntLookupContainer) { + if (hasEmptyKey && other.contains(0)) { + hasEmptyKey = false; + values[mask + 1] = 0L; + } + + final int[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + int existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (IntCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntLongPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(0, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0L; + } + } + + final int[] keys = this.keys; + final long[] values = this.values; + for (int slot = 0; slot <= mask; ) { + int existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(0)) { + hasEmptyKey = false; + values[mask + 1] = 0L; + } + } + + final int[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + int existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public long get(int key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : 0L; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0L; + } + } + + /** {@inheritDoc} */ + @Override + public long getOrDefault(int key, long defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(int key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(int key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public long indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public long indexReplace(int index, long newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + long previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, int key, long value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public long indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + long previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0L; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, 0); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (IntLongCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(IntLongHashMap other) { + if (other.size() != size()) { + return false; + } + + for (IntLongCursor c : other) { + int key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final int[] prevKeys = this.keys; + final long[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final IntLongCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new IntLongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntLongCursor fetch() { + final int mask = IntLongHashMap.this.mask; + while (index <= mask) { + int existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = 0; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final int[] keys = this.keys; + final long[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(0, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final int[] keys = this.keys; + final long[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(0, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { + private final IntLongHashMap owner = IntLongHashMap.this; + + @Override + public boolean contains(int e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((IntLongProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((IntLongPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(IntPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final int e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final IntCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new IntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntCursor fetch() { + final int mask = IntLongHashMap.this.mask; + while (index <= mask) { + int existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = 0; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public LongCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractLongCollection { + private final IntLongHashMap owner = IntLongHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(long value) { + for (IntLongCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (IntLongCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (IntLongCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final long e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final LongPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final LongCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new LongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongCursor fetch() { + final int mask = IntLongHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public IntLongHashMap clone() { + try { + + IntLongHashMap cloned = (IntLongHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (IntLongCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return IntBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static IntLongHashMap from(int[] keys, long[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + IntLongHashMap map = new IntLongHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(int key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(int[] fromKeys, long[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final int[] keys = this.keys; + final long[] values = this.values; + final int mask = this.mask; + int existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + int[] prevKeys = this.keys; + long[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new int[arraySize + emptyElementSlot]); + this.values = (new long[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, int pendingKey, long pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final int[] prevKeys = this.keys; + final long[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final int[] keys = this.keys; + final long[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final int existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = 0; + values[gapSlot] = 0L; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/IntLongMap.java b/src/main/java/com/carrotsearch/hppc/IntLongMap.java new file mode 100755 index 00000000..debb6908 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntLongMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.IntLongCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface IntLongMap extends IntLongAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public long get(int key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public long getOrDefault(int key, long defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public long put(int key, long value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(int key, long value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(IntLongAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public long putOrAdd(int key, long putValue, long incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public long addTo(int key, long additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public long remove(int key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link IntLongMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(int key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public long indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public long indexReplace(int index, long newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, int key, long value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public long indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntLookupContainer.java b/src/main/java/com/carrotsearch/hppc/IntLookupContainer.java new file mode 100755 index 00000000..7eee508f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntLookupContainer.java @@ -0,0 +1,12 @@ +package com.carrotsearch.hppc; + +/** + * Marker interface for containers that can check if they contain a given object in at least time + * O(log n) and ideally in amortized constant time O(1). + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeLookupContainer.java") +public interface IntLookupContainer extends IntContainer { + public boolean contains(int e); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntObjectAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/IntObjectAssociativeContainer.java new file mode 100755 index 00000000..7be49222 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntObjectAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see IntContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface IntObjectAssociativeContainer extends Iterable> { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator> iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(int key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntObjectPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link IntObjectProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public > T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link IntObjectPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public > T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public IntCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public ObjectContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/IntObjectHashMap.java new file mode 100755 index 00000000..8fb8f64f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntObjectHashMap.java @@ -0,0 +1,1050 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of int to Object, implemented using open addressing with + * linear probing for collision resolution. Supports null values. + * + * @see HPPC interfaces diagram + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class IntObjectHashMap + implements IntObjectMap, Preallocable, Cloneable, Accountable { + /** The array holding keys. */ + public int[] keys; + + /** The array holding values. */ + public Object[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public IntObjectHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public IntObjectHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public IntObjectHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public IntObjectHashMap(IntObjectAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public VType put(int key, VType value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + VType previousValue = hasEmptyKey ? (VType) values[mask + 1] : null; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final VType previousValue = (VType) values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return null; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(IntObjectAssociativeContainer container) { + final int count = size(); + for (IntObjectCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable> iterable) { + final int count = size(); + for (IntObjectCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** {@inheritDoc} */ + @Override + public VType remove(int key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return null; + } + hasEmptyKey = false; + VType previousValue = (VType) values[mask + 1]; + values[mask + 1] = null; + return previousValue; + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final VType previousValue = (VType) values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return null; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof IntLookupContainer) { + if (hasEmptyKey && other.contains(0)) { + hasEmptyKey = false; + values[mask + 1] = null; + } + + final int[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + int existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (IntCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntObjectPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(0, (VType) values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = null; + } + } + + final int[] keys = this.keys; + final VType[] values = (VType[]) this.values; + for (int slot = 0; slot <= mask; ) { + int existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(0)) { + hasEmptyKey = false; + values[mask + 1] = null; + } + } + + final int[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + int existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public VType get(int key) { + if (((key) == 0)) { + return hasEmptyKey ? (VType) values[mask + 1] : null; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return (VType) values[slot]; + } + slot = (slot + 1) & mask; + } + + return null; + } + } + + /** {@inheritDoc} */ + @Override + public VType getOrDefault(int key, VType defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? (VType) values[mask + 1] : defaultValue; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return (VType) values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(int key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(int key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public VType indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return (VType) values[index]; + } + + /** {@inheritDoc} */ + @Override + public VType indexReplace(int index, VType newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + VType previousValue = (VType) values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, int key, VType value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public VType indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + VType previousValue = (VType) values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = null; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, 0); + + Arrays.fill(values, null); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (IntObjectCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** + * Return true if all keys of some other container exist in this container. Values are compared + * using {@link Objects#equals(Object)} method. + */ + protected boolean equalElements(IntObjectHashMap other) { + if (other.size() != size()) { + return false; + } + + for (IntObjectCursor c : other) { + int key = c.key; + if (!containsKey(key) || !java.util.Objects.equals(c.value, get(key))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final int[] prevKeys = this.keys; + final VType[] prevValues = (VType[]) this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final IntObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new IntObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntObjectCursor fetch() { + final int mask = IntObjectHashMap.this.mask; + while (index <= mask) { + int existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = (VType) values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = 0; + cursor.value = (VType) values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator> iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T procedure) { + final int[] keys = this.keys; + final VType[] values = (VType[]) this.values; + + if (hasEmptyKey) { + procedure.apply(0, (VType) values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T predicate) { + final int[] keys = this.keys; + final VType[] values = (VType[]) this.values; + + if (hasEmptyKey) { + if (!predicate.apply(0, (VType) values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { + private final IntObjectHashMap owner = IntObjectHashMap.this; + + @Override + public boolean contains(int e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((IntObjectProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((IntObjectPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(IntPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final int e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final IntCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new IntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntCursor fetch() { + final int mask = IntObjectHashMap.this.mask; + while (index <= mask) { + int existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = 0; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public ObjectCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractObjectCollection { + private final IntObjectHashMap owner = IntObjectHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(VType value) { + for (IntObjectCursor c : owner) { + if (java.util.Objects.equals(value, c.value)) { + return true; + } + } + return false; + } + + @Override + public > T forEach(T procedure) { + for (IntObjectCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public > T forEach(T predicate) { + for (IntObjectCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator> iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final VType e) { + return owner.removeAll((key, value) -> java.util.Objects.equals(e, value)); + } + + @Override + public int removeAll(final ObjectPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator> { + private final ObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new ObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectCursor fetch() { + final int mask = IntObjectHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = (VType) values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = (VType) values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public IntObjectHashMap clone() { + try { + + IntObjectHashMap cloned = (IntObjectHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (IntObjectCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return IntBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static IntObjectHashMap from(int[] keys, VType[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + IntObjectHashMap map = new IntObjectHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(int key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(int[] fromKeys, VType[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final int[] keys = this.keys; + final VType[] values = (VType[]) this.values; + final int mask = this.mask; + int existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + int[] prevKeys = this.keys; + VType[] prevValues = (VType[]) this.values; + try { + int emptyElementSlot = 1; + this.keys = (new int[arraySize + emptyElementSlot]); + this.values = ((VType[]) new Object[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, int pendingKey, VType pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final int[] prevKeys = this.keys; + final VType[] prevValues = (VType[]) this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final int[] keys = this.keys; + final VType[] values = (VType[]) this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final int existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = 0; + values[gapSlot] = null; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/IntObjectMap.java b/src/main/java/com/carrotsearch/hppc/IntObjectMap.java new file mode 100755 index 00000000..86c778c7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntObjectMap.java @@ -0,0 +1,181 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.IntObjectCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface IntObjectMap extends IntObjectAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public VType get(int key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public VType getOrDefault(int key, VType defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public VType put(int key, VType value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(int key, VType value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(IntObjectAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable> iterable); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public VType remove(int key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link IntObjectMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(int key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public VType indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public VType indexReplace(int index, VType newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, int key, VType value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public VType indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntPgmIndex.java b/src/main/java/com/carrotsearch/hppc/IntPgmIndex.java new file mode 100755 index 00000000..da7dd0d2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntPgmIndex.java @@ -0,0 +1,600 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.IntCursor; +import com.carrotsearch.hppc.procedures.IntProcedure; +import java.util.Arrays; +import java.util.Iterator; + +/** + * Space-efficient index that enables fast rank/range search operations on a sorted sequence of + * int. + * + *

Implementation of the PGM-Index described at https://pgm.di.unipi.it/, based on the paper + * + *

+ *   Paolo Ferragina and Giorgio Vinciguerra.
+ *   The PGM-index: a fully-dynamic compressed learned index with provable worst-case bounds.
+ *   PVLDB, 13(8): 1162-1175, 2020.
+ * 
+ * + * It provides {@code rank} and {@code range} search operations. {@code indexOf()} is faster than + * B+Tree, and the index is much more compact. {@code contains()} is between 4x to 7x slower than + * {@code IntHashSet#contains()}, but between 2.5x to 3x faster than {@link Arrays#binarySearch}. + * + *

Its compactness (40KB for 200MB of keys) makes it efficient for very large collections, the + * index fitting easily in the L2 cache. The {@code epsilon} parameter should be set according to + * the desired space-time trade-off. A smaller value makes the estimation more precise and the range + * smaller but at the cost of increased space usage. In practice, {@code epsilon} 64 is a good sweet + * spot. + * + *

Internally the index uses an optimal piecewise linear mapping from keys to their position in + * the sorted order. This mapping is represented as a sequence of linear models (segments) which are + * themselves recursively indexed by other piecewise linear mappings. + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypePgmIndex.java") +public class IntPgmIndex implements Accountable { + + /** Empty immutable IntPgmIndex. */ + public static final IntPgmIndex EMPTY = new IntEmptyPgmIndex(); + + /** + * Epsilon approximation range when searching the list of keys. Controls the size of the returned + * search range, strictly greater than 0. It should be set according to the desired space-time + * trade-off. A smaller value makes the estimation more precise and the range smaller but at the + * cost of increased space usage. + * + *

With EPSILON=64 the benchmark with 200MB of keys shows that this PGM index requires only 2% + * additional memory on average (40KB). It depends on the distribution of the keys. This epsilon + * value is good even for 2MB of keys. With EPSILON=32: +5% speed, but 4x space (160KB). + */ + public static final int EPSILON = 64; + + /** + * Epsilon approximation range for the segments layers. Controls the size of the search range in + * the hierarchical segment lists, strictly greater than 0. + */ + public static final int EPSILON_RECURSIVE = 32; + + /** Size of a key, measured in {@link Integer#BYTES} because the key is stored in an int[]. */ + public static final int KEY_SIZE = + RamUsageEstimator.primitiveSizes.get(int.class) / Integer.BYTES; + + /** 2x {@link #KEY_SIZE}. */ + public static final int DOUBLE_KEY_SIZE = KEY_SIZE * 2; + + /** + * Data size of a segment, measured in {@link Integer#BYTES}, because segments are stored in an + * int[]. + */ + public static final int SEGMENT_DATA_SIZE = KEY_SIZE * 3; + + /** Initial value of the exponential jump when scanning out of the epsilon range. */ + public static final int BEYOND_EPSILON_JUMP = 16; + + /** + * The list of keys for which this index is built. It is sorted and may contain duplicate + * elements. + */ + public final IntArrayList keys; + + /** The size of the key set. That is, the number of distinct elements in {@link #keys}. */ + public final int size; + + /** The lowest key in {@link #keys}. */ + public final int firstKey; + + /** The highest key in {@link #keys}. */ + public final int lastKey; + + /** The epsilon range used to build this index. */ + public final int epsilon; + + /** The recursive epsilon range used to build this index. */ + public final int epsilonRecursive; + + /** The offsets in {@link #segmentData} of the first segment of each segment level. */ + public final int[] levelOffsets; + + /** The index data. It contains all the segments for all the levels. */ + public final int[] segmentData; + + private IntPgmIndex( + IntArrayList keys, + int size, + int epsilon, + int epsilonRecursive, + int[] levelOffsets, + int[] segmentData) { + assert keys.size() > 0; + assert size > 0 && size <= keys.size(); + assert epsilon > 0; + assert epsilonRecursive > 0; + this.keys = keys; + this.size = size; + firstKey = keys.get(0); + lastKey = keys.get(keys.size() - 1); + this.epsilon = epsilon; + this.epsilonRecursive = epsilonRecursive; + this.levelOffsets = levelOffsets; + this.segmentData = segmentData; + } + + /** Empty set constructor. */ + private IntPgmIndex() { + keys = new IntArrayList(0); + size = 0; + firstKey = 0; + lastKey = 0; + epsilon = 0; + epsilonRecursive = 0; + levelOffsets = new int[0]; + segmentData = levelOffsets; + } + + /** Returns the size of the key set. That is, the number of distinct elements in {@link #keys}. */ + public int size() { + return size; + } + + /** Returns whether this key set is empty. */ + public boolean isEmpty() { + return size() == 0; + } + + /** Returns whether this key set contains the given key. */ + public boolean contains(int key) { + return indexOf(key) >= 0; + } + + /** + * Searches the specified key, and returns its index in the element list. If multiple elements are + * equal to the specified key, there is no guarantee which one will be found. + * + * @return The index of the searched key if it is present; otherwise, {@code (-(insertion + * point) - 1)}. The insertion point is defined as the point at which the key would + * be inserted into the list: the index of the first element greater than the key, or {@link + * #keys}#{@code size()} if all the elements are less than the specified key. Note that this + * guarantees that the return value will be >= 0 if and only if the key is found. + */ + public int indexOf(int key) { + if (key < firstKey) { + return -1; + } + if (key > lastKey) { + return -keys.size() - 1; + } + final int[] segmentData = this.segmentData; + int segmentDataIndex = findSegment(key); + int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData); + int index = + Math.min( + approximateIndex(key, segmentDataIndex, segmentData), + Math.min(nextIntercept, keys.size() - 1)); + assert index >= 0 && index < keys.size(); + int k = keys.get(index); + if (key < k) { + // Scan sequentially before the approximated index, within epsilon range. + final int fromIndex = Math.max(index - epsilon - 1, 0); + while (--index >= fromIndex) { + k = keys.get(index); + if (key > k) { + return -index - 2; + } + if (((key) == (k))) { + return index; + } + } + // Continue scanning out of the epsilon range. + // This might happen in rare cases of precision error during the approximation + // computation for longs (we don't have long double 128 bits in Java). + // This might also happen in rare corner cases of large duplicate elements + // sequence at the epsilon range boundary. + index++; + int jump = BEYOND_EPSILON_JUMP; + do { + int loIndex = Math.max(index - jump, 0); + if (key >= keys.get(loIndex)) { + return Arrays.binarySearch(keys.buffer, loIndex, index, key); + } + index = loIndex; + jump <<= 1; + } while (index > 0); + return -1; + } else if (((key) == (k))) { + return index; + } else { + // Scan sequentially after the approximated index, within epsilon range. + final int toIndex = Math.min(index + epsilon + 3, keys.size()); + while (++index < toIndex) { + k = keys.get(index); + if (key < k) { + return -index - 1; + } + if (((key) == (k))) { + return index; + } + } + // Continue scanning out of the epsilon range. + int jump = BEYOND_EPSILON_JUMP; + do { + int hiIndex = Math.min(index + jump, keys.size()); + if (key <= keys.get(hiIndex)) { + return Arrays.binarySearch(keys.buffer, index, hiIndex, key); + } + index = hiIndex; + jump <<= 1; + } while (index < keys.size()); + return -keys.size() - 1; + } + } + + /** + * Returns, for any value {@code x}, the number of keys in the sorted list which are smaller than + * {@code x}. It is equal to {@link #indexOf} if {@code x} belongs to the list, or -{@link + * #indexOf}-1 otherwise. + * + *

If multiple elements are equal to the specified key, there is no guarantee which one will be + * found. + * + * @return The index of the searched key if it is present; otherwise, the {@code insertion point}. + * The insertion point is defined as the point at which the key would be inserted into + * the list: the index of the first element greater than the key, or {@link #keys}#{@code + * size()} if all the elements are less than the specified key. Note that this method always + * returns a value >= 0. + */ + public int rank(int x) { + int index = indexOf(x); + return index >= 0 ? index : -index - 1; + } + + /** + * Returns the number of keys in the list that are greater than or equal to {@code minKey} + * (inclusive), and less than or equal to {@code maxKey} (inclusive). + */ + public int rangeCardinality(int minKey, int maxKey) { + int fromIndex = rank(minKey); + int maxIndex = indexOf(maxKey); + int toIndex = maxIndex >= 0 ? maxIndex + 1 : -maxIndex - 1; + return Math.max(toIndex - fromIndex, 0); + } + + /** + * Returns an iterator over the keys in the list that are greater than or equal to {@code minKey} + * (inclusive), and less than or equal to {@code maxKey} (inclusive). + */ + public Iterator rangeIterator(int minKey, int maxKey) { + int fromIndex = rank(minKey); + return new RangeIterator(keys, fromIndex, maxKey); + } + + /** + * Applies {@code procedure} to the keys in the list that are greater than or equal to {@code + * minKey} (inclusive), and less than or equal to {@code maxKey} (inclusive). + */ + public T forEachInRange(T procedure, int minKey, int maxKey) { + final int[] buffer = keys.buffer; + int k; + for (int i = rank(minKey), size = keys.size(); i < size && (k = buffer[i]) <= maxKey; i++) { + procedure.apply(k); + } + return procedure; + } + + /** + * Estimates the allocated memory. It does not count the memory for the list of keys, only for the + * index itself. + */ + @Override + public long ramBytesAllocated() { + // int: size, epsilon, epsilonRecursive + // int: firstKey, lastKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 3 * Integer.BYTES + + 2L * KEY_SIZE * Integer.BYTES + // + keys.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(levelOffsets) + + RamUsageEstimator.shallowSizeOfArray(segmentData); + } + + /** + * Estimates the bytes that are actually used. It does not count the memory for the list of keys, + * only for the index itself. + */ + @Override + public long ramBytesUsed() { + // int: size, epsilon, epsilonRecursive + // int: firstKey, lastKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 3 * Integer.BYTES + + 2L * KEY_SIZE * Integer.BYTES + // + keys.ramBytesUsed() + + RamUsageEstimator.shallowSizeOfArray(levelOffsets) + + RamUsageEstimator.shallowSizeOfArray(segmentData); + } + + /** + * Finds the segment responsible for a given key, that is, the rightmost segment having its first + * key <= the searched key. + * + * @return the segment data index; or -1 if none. + */ + private int findSegment(int key) { + assert key >= firstKey && key <= lastKey; + final int epsilonRecursive = this.epsilonRecursive; + final int[] levelOffsets = this.levelOffsets; + final int[] segmentData = this.segmentData; + int level = levelOffsets.length - 1; + int segmentDataIndex = levelOffsets[level] * SEGMENT_DATA_SIZE; + while (--level >= 0) { + int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData); + int index = Math.min(approximateIndex(key, segmentDataIndex, segmentData), nextIntercept); + assert index >= 0 && index <= levelOffsets[level + 1] - levelOffsets[level] - 1; + int sdIndex = (levelOffsets[level] + index) * SEGMENT_DATA_SIZE; + if (getKey(sdIndex, segmentData) <= key) { + // Scan sequentially segments after the approximated index, within the epsilon range. + final int levelNumSegments = levelOffsets[level + 1] - levelOffsets[level] - 1; + final int toIndex = Math.min(index + epsilonRecursive + 3, levelNumSegments); + while (index++ < toIndex && getKey(sdIndex + SEGMENT_DATA_SIZE, segmentData) <= key) { + sdIndex += SEGMENT_DATA_SIZE; + } + } else { + // Scan sequentially segments before the approximated index, within the epsilon range. + final int fromIndex = Math.max(index - epsilonRecursive - 1, 0); + while (index-- > fromIndex) { + sdIndex -= SEGMENT_DATA_SIZE; + if (getKey(sdIndex, segmentData) <= key) { + break; + } + } + } + segmentDataIndex = sdIndex; + } + assert segmentDataIndex >= 0; + return segmentDataIndex; + } + + private int approximateIndex(int key, int segmentDataIndex, int[] segmentData) { + long intercept = getIntercept(segmentDataIndex, segmentData); + int sKey = getKey(segmentDataIndex, segmentData); + double slope = getSlope(segmentDataIndex, segmentData); + int index = (int) (slope * ((double) key - sKey) + intercept); + return Math.max(index, 0); + } + + private static long getIntercept(int segmentDataIndex, int[] segmentData) { + return PgmIndexUtil.getIntercept(segmentDataIndex, segmentData, KEY_SIZE); + } + + private int getKey(int segmentDataIndex, int[] segmentData) { + return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0); + } + + private static double getSlope(int segmentDataIndex, int[] segmentData) { + return PgmIndexUtil.getSlope(segmentDataIndex + DOUBLE_KEY_SIZE, segmentData, KEY_SIZE); + } + + /** Empty immutable PGM Index. */ + private static class IntEmptyPgmIndex extends IntPgmIndex { + + private final Iterator emptyIterator = new IntEmptyIterator(); + + @Override + public int indexOf(int key) { + return -1; + } + + @Override + public Iterator rangeIterator(int minKey, int maxKey) { + return emptyIterator; + } + + @Override + public T forEachInRange(T procedure, int minKey, int maxKey) { + return procedure; + } + + private static class IntEmptyIterator extends AbstractIterator { + @Override + protected IntCursor fetch() { + return done(); + } + } + } + + /** Iterator over a range of elements in a sorted array. */ + protected static class RangeIterator extends AbstractIterator { + private final int[] buffer; + private final int size; + private final IntCursor cursor; + private final int maxKey; + + /** Range iterator from {@code fromIndex} (inclusive) to {@code maxKey} (inclusive). */ + protected RangeIterator(IntArrayList keys, int fromIndex, int maxKey) { + this.buffer = keys.buffer; + this.size = keys.size(); + this.cursor = new IntCursor(); + this.cursor.index = fromIndex; + this.maxKey = maxKey; + } + + @Override + protected IntCursor fetch() { + if (cursor.index >= size) { + return done(); + } + cursor.value = buffer[cursor.index++]; + if (cursor.value > maxKey) { + cursor.index = size; + return done(); + } + return cursor; + } + } + + /** Builds a {@link IntPgmIndex} on a provided sorted list of keys. */ + public static class IntBuilder implements PlaModel.SegmentConsumer, Accountable { + + protected IntArrayList keys; + protected int epsilon = EPSILON; + protected int epsilonRecursive = EPSILON_RECURSIVE; + protected PlaModel plam; + protected int size; + protected IntArrayList segmentData; + protected int numSegments; + + /** Sets the sorted list of keys to build the index for; duplicate elements are allowed. */ + public IntBuilder setSortedKeys(IntArrayList keys) { + this.keys = keys; + return this; + } + + /** Sets the sorted array of keys to build the index for; duplicate elements are allowed. */ + public IntBuilder setSortedKeys(int[] keys, int length) { + IntArrayList keyList = new IntArrayList(0); + keyList.buffer = keys; + keyList.elementsCount = length; + return setSortedKeys(keyList); + } + + /** Sets the epsilon range to use when learning the segments for the list of keys. */ + public IntBuilder setEpsilon(int epsilon) { + if (epsilon <= 0) { + throw new IllegalArgumentException("epsilon must be > 0"); + } + this.epsilon = epsilon; + return this; + } + + /** + * Sets the recursive epsilon range to use when learning the segments for the segment levels. + */ + public IntBuilder setEpsilonRecursive(int epsilonRecursive) { + if (epsilonRecursive <= 0) { + throw new IllegalArgumentException("epsilonRecursive must be > 0"); + } + this.epsilonRecursive = epsilonRecursive; + return this; + } + + /** Builds the {@link IntPgmIndex}; or {@link #EMPTY} if there are no keys in the list. */ + public IntPgmIndex build() { + if (keys == null || keys.size() == 0) { + return (IntPgmIndex) EMPTY; + } + plam = new PlaModel(epsilon); + + int segmentsInitialCapacity = + Math.min( + Math.max(keys.size() / (2 * epsilon * epsilon) * SEGMENT_DATA_SIZE, 16), 1 << 19); + segmentData = new IntArrayList(segmentsInitialCapacity); + IntArrayList levelOffsets = new IntArrayList(16); + + int levelOffset = 0; + levelOffsets.add(levelOffset); + int levelNumSegments = buildFirstLevel(); + while (levelNumSegments > 1) { + int nextLevelOffset = numSegments; + levelOffsets.add(nextLevelOffset); + levelNumSegments = buildUpperLevel(levelOffset, levelNumSegments); + levelOffset = nextLevelOffset; + } + + int[] segmentDataFinal = segmentData.toArray(); + int[] levelOffsetsFinal = levelOffsets.toArray(); + return new IntPgmIndex( + keys, size, epsilon, epsilonRecursive, levelOffsetsFinal, segmentDataFinal); + } + + private int buildFirstLevel() { + assert numSegments == 0; + int numKeys = keys.size(); + int size = 0; + int key = keys.get(0); + size++; + plam.addKey(key, 0, this); + for (int i = 1; i < numKeys; i++) { + int nextKey = keys.get(i); + if (!((nextKey) == (key))) { + key = nextKey; + plam.addKey(key, i, this); + size++; + } + } + plam.finish(this); + addSentinelSegment(numKeys); + this.size = size; + return numSegments - 1; + } + + private int buildUpperLevel(int levelOffset, int levelNumSegments) { + plam.setEpsilon(epsilonRecursive); + assert numSegments > 0; + int initialNumSegments = numSegments; + int segmentDataIndex = levelOffset * SEGMENT_DATA_SIZE; + int key = getKey(segmentDataIndex, segmentData.buffer); + plam.addKey(key, 0, this); + for (int i = 1; i < levelNumSegments; i++) { + segmentDataIndex += SEGMENT_DATA_SIZE; + int nextKey = getKey(segmentDataIndex, segmentData.buffer); + if (!((nextKey) == (key))) { + key = nextKey; + plam.addKey(key, i, this); + } + } + plam.finish(this); + addSentinelSegment(levelNumSegments); + return numSegments - initialNumSegments - 1; + } + + private int getKey(int segmentDataIndex, int[] segmentData) { + return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0); + } + + /** + * Adds a sentinel segment that is used to give a limit for the position approximation, but does + * not count in the number of segments per level. + */ + private void addSentinelSegment(int endIndex) { + // This sentinel segment is used in findSegment(). + accept(Double.MAX_VALUE, 0d, endIndex); + } + + @Override + public void accept(double firstKey, double slope, long intercept) { + PgmIndexUtil.addIntercept(intercept, segmentData, KEY_SIZE); + PgmIndexUtil.addKey((int) firstKey, segmentData); + PgmIndexUtil.addSlope(slope, segmentData, KEY_SIZE); + numSegments++; + assert segmentData.size() == numSegments * SEGMENT_DATA_SIZE; + } + + /** + * Estimates the allocated memory. It does not count the memory for the list of keys, only for + * the builder itself. + */ + @Override + public long ramBytesAllocated() { + // int: epsilon, epsilonRecursive, size, numSegments + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + // + keys.ramBytesAllocated() + + plam.ramBytesAllocated() + + segmentData.ramBytesAllocated(); + } + + /** + * Estimates the bytes that are actually used. It does not count the memory for the list of + * keys, only for the builder itself. + */ + @Override + public long ramBytesUsed() { + // int: epsilon, epsilonRecursive, size, numSegments + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + // + keys.ramBytesUsed() + + plam.ramBytesUsed() + + segmentData.ramBytesUsed(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/IntSet.java b/src/main/java/com/carrotsearch/hppc/IntSet.java new file mode 100755 index 00000000..500b376e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntSet.java @@ -0,0 +1,33 @@ +package com.carrotsearch.hppc; + +/** A set of ints. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeSet.java") +public interface IntSet extends IntCollection { + /** + * Adds k to the set. + * + * @return Returns true if this element was not part of the set before. Returns + * false if an equal element is already part of the set, does not replace the + * existing element with the argument. + */ + public boolean add(int k); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); + + /** + * Adds all elements from the given {@link IntContainer} to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + * @since 0.9.1 + */ + public int addAll(IntContainer container); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntShortAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/IntShortAssociativeContainer.java new file mode 100755 index 00000000..918efde7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntShortAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see IntContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface IntShortAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(int key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(IntShortPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link IntShortProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link IntShortPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public IntCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public ShortContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntShortHashMap.java b/src/main/java/com/carrotsearch/hppc/IntShortHashMap.java new file mode 100755 index 00000000..c36b0fe2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntShortHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of int to short, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeHashMap.java") +public class IntShortHashMap implements IntShortMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public int[] keys; + + /** The array holding values. */ + public short[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public IntShortHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public IntShortHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public IntShortHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public IntShortHashMap(IntShortAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public short put(int key, short value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + short previousValue = hasEmptyKey ? values[mask + 1] : ((short) 0); + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final short previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return ((short) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(IntShortAssociativeContainer container) { + final int count = size(); + for (IntShortCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (IntShortCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public short putOrAdd(int key, short putValue, short incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((short) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public short addTo(int key, short incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public short remove(int key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return ((short) 0); + } + hasEmptyKey = false; + short previousValue = values[mask + 1]; + values[mask + 1] = ((short) 0); + return previousValue; + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final short previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return ((short) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof IntLookupContainer) { + if (hasEmptyKey && other.contains(0)) { + hasEmptyKey = false; + values[mask + 1] = ((short) 0); + } + + final int[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + int existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (IntCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntShortPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(0, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = ((short) 0); + } + } + + final int[] keys = this.keys; + final short[] values = this.values; + for (int slot = 0; slot <= mask; ) { + int existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(IntPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(0)) { + hasEmptyKey = false; + values[mask + 1] = ((short) 0); + } + } + + final int[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + int existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public short get(int key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : ((short) 0); + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return ((short) 0); + } + } + + /** {@inheritDoc} */ + @Override + public short getOrDefault(int key, short defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(int key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final int[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(int key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final int[] keys = this.keys; + int slot = hashKey(key) & mask; + + int existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public short indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public short indexReplace(int index, short newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + short previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, int key, short value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public short indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + short previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = ((short) 0); + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, 0); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (IntShortCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(IntShortHashMap other) { + if (other.size() != size()) { + return false; + } + + for (IntShortCursor c : other) { + int key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final int[] prevKeys = this.keys; + final short[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final IntShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new IntShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntShortCursor fetch() { + final int mask = IntShortHashMap.this.mask; + while (index <= mask) { + int existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = 0; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final int[] keys = this.keys; + final short[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(0, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final int[] keys = this.keys; + final short[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(0, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { + private final IntShortHashMap owner = IntShortHashMap.this; + + @Override + public boolean contains(int e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((IntShortProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((IntShortPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(IntPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final int e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final IntCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new IntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntCursor fetch() { + final int mask = IntShortHashMap.this.mask; + while (index <= mask) { + int existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = 0; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public ShortCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractShortCollection { + private final IntShortHashMap owner = IntShortHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(short value) { + for (IntShortCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (IntShortCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (IntShortCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final short e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final ShortPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new ShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortCursor fetch() { + final int mask = IntShortHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public IntShortHashMap clone() { + try { + + IntShortHashMap cloned = (IntShortHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (IntShortCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return IntBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static IntShortHashMap from(int[] keys, short[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + IntShortHashMap map = new IntShortHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(int key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(int[] fromKeys, short[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final int[] keys = this.keys; + final short[] values = this.values; + final int mask = this.mask; + int existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + int[] prevKeys = this.keys; + short[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new int[arraySize + emptyElementSlot]); + this.values = (new short[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, int pendingKey, short pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final int[] prevKeys = this.keys; + final short[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final int[] keys = this.keys; + final short[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final int existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = 0; + values[gapSlot] = ((short) 0); + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/IntShortMap.java b/src/main/java/com/carrotsearch/hppc/IntShortMap.java new file mode 100755 index 00000000..b0a5813a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntShortMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.IntShortCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface IntShortMap extends IntShortAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public short get(int key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public short getOrDefault(int key, short defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public short put(int key, short value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(int key, short value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(IntShortAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public short putOrAdd(int key, short putValue, short incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public short addTo(int key, short additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public short remove(int key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link IntShortMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(int key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public short indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public short indexReplace(int index, short newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, int key, short value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public short indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/IntStack.java b/src/main/java/com/carrotsearch/hppc/IntStack.java new file mode 100755 index 00000000..cd65ff61 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntStack.java @@ -0,0 +1,137 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.IntCursor; + +/** + * A subclass of {@link IntArrayList} adding stack-related utility methods. The top of the stack is + * at the {@link #size()} - 1 element. + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java") +public class IntStack extends IntArrayList { + /** New instance with sane defaults. */ + public IntStack() { + super(); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public IntStack(int expectedElements) { + super(expectedElements); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public IntStack(int expectedElements, ArraySizingStrategy resizer) { + super(expectedElements, resizer); + } + + /** Create a stack by pushing all elements of another container to it. */ + public IntStack(IntContainer container) { + super(container); + } + + /** Adds one int to the stack. */ + public void push(int e1) { + ensureBufferSpace(1); + buffer[elementsCount++] = e1; + } + + /** Adds two ints to the stack. */ + public void push(int e1, int e2) { + ensureBufferSpace(2); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + } + + /** Adds three ints to the stack. */ + public void push(int e1, int e2, int e3) { + ensureBufferSpace(3); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + buffer[elementsCount++] = e3; + } + + /** Adds four ints to the stack. */ + public void push(int e1, int e2, int e3, int e4) { + ensureBufferSpace(4); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + buffer[elementsCount++] = e3; + buffer[elementsCount++] = e4; + } + + /** Add a range of array elements to the stack. */ + public void push(int[] elements, int start, int len) { + assert start >= 0 && len >= 0; + + ensureBufferSpace(len); + System.arraycopy(elements, start, buffer, elementsCount, len); + elementsCount += len; + } + + /** + * Vararg-signature method for pushing elements at the top of the stack. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + */ + public final void push(int... elements) { + push(elements, 0, elements.length); + } + + /** Pushes all elements from another container to the top of the stack. */ + public int pushAll(IntContainer container) { + return addAll(container); + } + + /** Pushes all elements from another iterable to the top of the stack. */ + public int pushAll(Iterable iterable) { + return addAll(iterable); + } + + /** Discard an arbitrary number of elements from the top of the stack. */ + public void discard(int count) { + assert elementsCount >= count; + + elementsCount -= count; + } + + /** Discard the top element from the stack. */ + public void discard() { + assert elementsCount > 0; + + elementsCount--; + } + + /** Remove the top element from the stack and return it. */ + public int pop() { + return removeLast(); + } + + /** Peek at the top element on the stack. */ + public int peek() { + assert elementsCount > 0; + return buffer[elementsCount - 1]; + } + + /** Create a stack by pushing a variable number of arguments to it. */ + public static IntStack from(int... elements) { + final IntStack stack = new IntStack(elements.length); + stack.push(elements); + return stack; + } + + /** {@inheritDoc} */ + @Override + public IntStack clone() { + return (IntStack) super.clone(); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/LongArrayDeque.java b/src/main/java/com/carrotsearch/hppc/LongArrayDeque.java new file mode 100755 index 00000000..8065aafd --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongArrayDeque.java @@ -0,0 +1,776 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; + +import com.carrotsearch.hppc.cursors.LongCursor; +import com.carrotsearch.hppc.predicates.LongPredicate; +import com.carrotsearch.hppc.procedures.LongProcedure; +import java.util.*; + +/** An array-backed {@link LongDeque}. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java") +public class LongArrayDeque extends AbstractLongCollection + implements LongDeque, Preallocable, Cloneable, Accountable { + + /** Reuse the same strategy instance. */ + private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = + BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; + + /** Internal array for storing elements of the deque. */ + public long[] buffer = LongArrayList.EMPTY_ARRAY; + + /** + * The index of the element at the head of the deque or an arbitrary number equal to tail if the + * deque is empty. + */ + public int head; + + /** The index at which the next element would be added to the tail of the deque. */ + public int tail; + + /** Buffer resizing strategy. */ + protected final ArraySizingStrategy resizer; + + /** New instance with sane defaults. */ + public LongArrayDeque() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public LongArrayDeque(int expectedElements) { + this(expectedElements, DEFAULT_SIZING_STRATEGY); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public LongArrayDeque(int expectedElements, ArraySizingStrategy resizer) { + assert resizer != null; + this.resizer = resizer; + ensureCapacity(expectedElements); + } + + /** + * Creates a new deque from elements of another container, appending elements at the end of the + * deque in the iteration order. + */ + public LongArrayDeque(LongContainer container) { + this(container.size()); + addLast(container); + } + + /** {@inheritDoc} */ + @Override + public void addFirst(long e1) { + int h = oneLeft(head, buffer.length); + if (h == tail) { + ensureBufferSpace(1); + h = oneLeft(head, buffer.length); + } + buffer[head = h] = e1; + } + + /** + * Vararg-signature method for adding elements at the front of this deque. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + * + * @param elements The elements to add. + */ + public final void addFirst(long... elements) { + ensureBufferSpace(elements.length); + for (long k : elements) { + addFirst(k); + } + } + + /** + * Inserts all elements from the given container to the front of this deque. + * + * @param container The container to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addFirst(LongContainer container) { + int size = container.size(); + ensureBufferSpace(size); + + for (LongCursor cursor : container) { + addFirst(cursor.value); + } + + return size; + } + + /** + * Inserts all elements from the given iterable to the front of this deque. + * + * @param iterable The iterable to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addFirst(Iterable iterable) { + int size = 0; + for (LongCursor cursor : iterable) { + addFirst(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public void addLast(long e1) { + int t = oneRight(tail, buffer.length); + if (head == t) { + ensureBufferSpace(1); + t = oneRight(tail, buffer.length); + } + buffer[tail] = e1; + tail = t; + } + + /** + * Vararg-signature method for adding elements at the end of this deque. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + * + * @param elements The elements to iterate over. + */ + public final void addLast(long... elements) { + ensureBufferSpace(1); + for (long k : elements) { + addLast(k); + } + } + + /** + * Inserts all elements from the given container to the end of this deque. + * + * @param container The container to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addLast(LongContainer container) { + int size = container.size(); + ensureBufferSpace(size); + + for (LongCursor cursor : container) { + addLast(cursor.value); + } + + return size; + } + + /** + * Inserts all elements from the given iterable to the end of this deque. + * + * @param iterable The iterable to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addLast(Iterable iterable) { + int size = 0; + for (LongCursor cursor : iterable) { + addLast(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public long removeFirst() { + assert size() > 0 : "The deque is empty."; + + final long result = buffer[head]; + buffer[head] = 0L; + head = oneRight(head, buffer.length); + return result; + } + + /** {@inheritDoc} */ + @Override + public long removeLast() { + assert size() > 0 : "The deque is empty."; + + tail = oneLeft(tail, buffer.length); + final long result = buffer[tail]; + buffer[tail] = 0L; + return result; + } + + /** {@inheritDoc} */ + @Override + public long getFirst() { + assert size() > 0 : "The deque is empty."; + + return buffer[head]; + } + + /** {@inheritDoc} */ + @Override + public long getLast() { + assert size() > 0 : "The deque is empty."; + + return buffer[oneLeft(tail, buffer.length)]; + } + + /** {@inheritDoc} */ + @Override + public int removeFirst(long e1) { + final int index = bufferIndexOf(e1); + if (index >= 0) removeAtBufferIndex(index); + return index; + } + + /** + * Return the index of the first (counting from head) element equal to e1. The index + * points to the {@link #buffer} array. + * + * @param e1 The element to look for. + * @return Returns the index of the first element equal to e1 or -1 if + * not found. + */ + public int bufferIndexOf(long e1) { + final int last = tail; + final int bufLen = buffer.length; + for (int i = head; i != last; i = oneRight(i, bufLen)) { + if (((e1) == (buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int removeLast(long e1) { + final int index = lastBufferIndexOf(e1); + if (index >= 0) { + removeAtBufferIndex(index); + } + return index; + } + + /** + * Return the index of the last (counting from tail) element equal to e1. The index + * points to the {@link #buffer} array. + * + * @param e1 The element to look for. + * @return Returns the index of the first element equal to e1 or -1 if + * not found. + */ + public int lastBufferIndexOf(long e1) { + final int bufLen = buffer.length; + final int last = oneLeft(head, bufLen); + for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) { + if (((e1) == (buffer[i]))) return i; + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(long e1) { + int removed = 0; + final int last = tail; + final int bufLen = buffer.length; + int from, to; + for (from = to = head; from != last; from = oneRight(from, bufLen)) { + if (((e1) == (buffer[from]))) { + buffer[from] = 0L; + removed++; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0L; + } + + to = oneRight(to, bufLen); + } + + tail = to; + return removed; + } + + /** + * Removes the element at index in the internal {#link {@link #buffer} array, + * returning its value. + * + * @param index Index of the element to remove. The index must be located between {@link #head} + * and {@link #tail} in modulo {@link #buffer} arithmetic. + */ + public void removeAtBufferIndex(int index) { + assert (head <= tail ? index >= head && index < tail : index >= head || index < tail) + : "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ")."; + + // Cache fields in locals (hopefully moved to registers). + final long[] buffer = this.buffer; + final int bufLen = buffer.length; + final int lastIndex = bufLen - 1; + final int head = this.head; + final int tail = this.tail; + + final int leftChunk = Math.abs(index - head) % bufLen; + final int rightChunk = Math.abs(tail - index) % bufLen; + + if (leftChunk < rightChunk) { + if (index >= head) { + System.arraycopy(buffer, head, buffer, head + 1, leftChunk); + } else { + System.arraycopy(buffer, 0, buffer, 1, index); + buffer[0] = buffer[lastIndex]; + System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head); + } + buffer[head] = 0L; + this.head = oneRight(head, bufLen); + } else { + if (index < tail) { + System.arraycopy(buffer, index + 1, buffer, index, rightChunk); + } else { + System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index); + buffer[lastIndex] = buffer[0]; + System.arraycopy(buffer, 1, buffer, 0, tail); + } + buffer[tail] = 0L; + this.tail = oneLeft(tail, bufLen); + } + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int size() { + if (head <= tail) return tail - head; + else return (tail - head + buffer.length); + } + + /** + * {@inheritDoc} + * + *

The internal array buffers are not released as a result of this call. + * + * @see #release() + */ + @Override + public void clear() { + if (head < tail) { + Arrays.fill(buffer, head, tail, 0L); + } else { + Arrays.fill(buffer, 0, tail, 0L); + Arrays.fill(buffer, head, buffer.length, 0L); + } + this.head = tail = 0; + } + + /** Release internal buffers of this deque and reallocate with the default buffer. */ + public void release() { + this.head = tail = 0; + buffer = LongArrayList.EMPTY_ARRAY; + ensureBufferSpace(0); + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + ensureBufferSpace(expectedElements - size()); + } + + /** + * Ensures the internal buffer has enough free slots to store expectedAdditions. + * Increases internal buffer size if needed. + */ + protected void ensureBufferSpace(int expectedAdditions) { + final int bufferLen = buffer.length; + final int elementsCount = size(); + + if (elementsCount + expectedAdditions >= bufferLen) { + final int emptySlot = 1; // deque invariant: always an empty slot. + final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions); + assert newSize >= (elementsCount + expectedAdditions + emptySlot) + : "Resizer failed to" + + " return sensible new size: " + + newSize + + " <= " + + (elementsCount + expectedAdditions); + + try { + final long[] newBuffer = (new long[newSize]); + if (bufferLen > 0) { + toArray(newBuffer); + tail = elementsCount; + head = 0; + } + this.buffer = newBuffer; + } catch (OutOfMemoryError e) { + throw new BufferAllocationException( + "Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize); + } + } + } + + /** {@inheritDoc} */ + @Override + public long[] toArray() { + + final int size = size(); + return toArray((new long[size])); + } + + /** + * Copies elements of this deque to an array. The content of the target array is + * filled from index 0 (head of the queue) to index size() - 1 (tail of the queue). + * + * @param target The target array must be large enough to hold all elements. + * @return Returns the target argument for chaining. + */ + public long[] toArray(long[] target) { + assert target.length >= size() : "Target array must be >= " + size(); + + if (head < tail) { + // The contents is not wrapped around. Just copy. + System.arraycopy(buffer, head, target, 0, size()); + } else if (head > tail) { + // The contents is split. Merge elements from the following indexes: + // [head...buffer.length - 1][0, tail - 1] + final int rightCount = buffer.length - head; + System.arraycopy(buffer, head, target, 0, rightCount); + System.arraycopy(buffer, 0, target, rightCount, tail); + } + + return target; + } + + /** + * Clone this object. The returned clone will reuse the same hash function and array resizing + * strategy. + */ + @Override + public LongArrayDeque clone() { + try { + + LongArrayDeque cloned = (LongArrayDeque) super.clone(); + cloned.buffer = buffer.clone(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Move one index to the left, wrapping around buffer. */ + protected static int oneLeft(int index, int modulus) { + if (index >= 1) { + return index - 1; + } + return modulus - 1; + } + + /** Move one index to the right, wrapping around buffer. */ + protected static int oneRight(int index, int modulus) { + if (index + 1 == modulus) { + return 0; + } + return index + 1; + } + + @Override + public long ramBytesAllocated() { + // int: head, tail + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES * 2 + + resizer.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(buffer); + } + + @Override + public long ramBytesUsed() { + // int: head, tail + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES * 2 + + resizer.ramBytesUsed() + + RamUsageEstimator.shallowUsedSizeOfArray(buffer, size()); + } + + /** An iterator implementation for {@link ObjectArrayDeque#iterator}. */ + private final class ValueIterator extends AbstractIterator { + private final LongCursor cursor; + private int remaining; + + public ValueIterator() { + cursor = new LongCursor(); + cursor.index = oneLeft(head, buffer.length); + this.remaining = size(); + } + + @Override + protected LongCursor fetch() { + if (remaining == 0) { + return done(); + } + + remaining--; + cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)]; + return cursor; + } + } + + /** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */ + private final class DescendingValueIterator extends AbstractIterator { + private final LongCursor cursor; + private int remaining; + + public DescendingValueIterator() { + cursor = new LongCursor(); + cursor.index = tail; + this.remaining = size(); + } + + @Override + protected LongCursor fetch() { + if (remaining == 0) return done(); + + remaining--; + cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)]; + return cursor; + } + } + + /** + * Returns a cursor over the values of this deque (in head to tail order). The iterator is + * implemented as a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in + * the deque's buffer) use the cursor's public fields. An example is shown below. + * + *

+   * for (IntValueCursor c : intDeque) {
+   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator iterator() { + return new ValueIterator(); + } + + /** + * Returns a cursor over the values of this deque (in tail to head order). The iterator is + * implemented as a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in + * the deque's buffer) use the cursor's public fields. An example is shown below. + * + *
+   * for (Iterator<IntCursor> i = intDeque.descendingIterator(); i.hasNext();) {
+   *   final IntCursor c = i.next();
+   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator descendingIterator() { + return new DescendingValueIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + forEach(procedure, head, tail); + return procedure; + } + + /** + * Applies procedure to a slice of the deque, fromIndex, inclusive, to + * toIndex, exclusive. + */ + private void forEach(LongProcedure procedure, int fromIndex, final int toIndex) { + final long[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + procedure.apply(buffer[i]); + } + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + int fromIndex = head; + int toIndex = tail; + + final long[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + if (!predicate.apply(buffer[i])) { + break; + } + } + + return predicate; + } + + /** Applies procedure to all elements of this deque, tail to head. */ + @Override + public T descendingForEach(T procedure) { + descendingForEach(procedure, head, tail); + return procedure; + } + + /** + * Applies procedure to a slice of the deque, toIndex, exclusive, down + * to fromIndex, inclusive. + */ + private void descendingForEach(LongProcedure procedure, int fromIndex, final int toIndex) { + if (fromIndex == toIndex) return; + + final long[] buffer = this.buffer; + int i = toIndex; + do { + i = oneLeft(i, buffer.length); + procedure.apply(buffer[i]); + } while (i != fromIndex); + } + + /** {@inheritDoc} */ + @Override + public T descendingForEach(T predicate) { + descendingForEach(predicate, head, tail); + return predicate; + } + + /** + * Applies predicate to a slice of the deque, toIndex, exclusive, down + * to fromIndex, inclusive or until the predicate returns false. + */ + private void descendingForEach(LongPredicate predicate, int fromIndex, final int toIndex) { + if (fromIndex == toIndex) return; + + final long[] buffer = this.buffer; + int i = toIndex; + do { + i = oneLeft(i, buffer.length); + if (!predicate.apply(buffer[i])) { + break; + } + } while (i != fromIndex); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongPredicate predicate) { + final long[] buffer = this.buffer; + final int last = tail; + final int bufLen = buffer.length; + int removed = 0; + int from, to; + from = to = head; + try { + for (from = to = head; from != last; from = oneRight(from, bufLen)) { + if (predicate.apply(buffer[from])) { + buffer[from] = 0L; + removed++; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0L; + } + + to = oneRight(to, bufLen); + } + } finally { + // Keep the deque in consistent state even if the predicate throws an exception. + for (; from != last; from = oneRight(from, bufLen)) { + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0L; + } + + to = oneRight(to, bufLen); + } + tail = to; + } + + return removed; + } + + /** {@inheritDoc} */ + @Override + public boolean contains(long e) { + int fromIndex = head; + int toIndex = tail; + + final long[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + if (((e) == (buffer[i]))) { + return true; + } + } + + return false; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 1; + int fromIndex = head; + int toIndex = tail; + + final long[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + h = 31 * h + BitMixer.mix(this.buffer[i]); + } + return h; + } + + /** + * Returns true only if the other object is an instance of the same class and with + * the same elements. + */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Compare order-aligned elements against another {@link LongDeque}. */ + protected boolean equalElements(LongArrayDeque other) { + int max = size(); + if (other.size() != max) { + return false; + } + + Iterator i1 = this.iterator(); + Iterator i2 = other.iterator(); + + while (i1.hasNext() && i2.hasNext()) { + if (!((i1.next().value) == (i2.next().value))) { + return false; + } + } + + return !i1.hasNext() && !i2.hasNext(); + } + + /** Create a new deque by pushing a variable number of arguments to the end of it. */ + public static LongArrayDeque from(long... elements) { + final LongArrayDeque coll = new LongArrayDeque(elements.length); + coll.addLast(elements); + return coll; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/LongArrayList.java b/src/main/java/com/carrotsearch/hppc/LongArrayList.java new file mode 100755 index 00000000..ea99bfeb --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongArrayList.java @@ -0,0 +1,586 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.LongPredicate; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; +import java.util.stream.LongStream; + +/** An array-backed list of longs. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java") +public class LongArrayList extends AbstractLongCollection + implements LongIndexedContainer, Preallocable, Cloneable, Accountable { + /** An immutable empty buffer (array). */ + public static final long[] EMPTY_ARRAY = new long[0]; + + ; + + /** Reuse the same strategy instance. */ + private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = + BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; + + /** + * Internal array for storing the list. The array may be larger than the current size ({@link + * #size()}). + */ + public long[] buffer = EMPTY_ARRAY; + + /** Current number of elements stored in {@link #buffer}. */ + public int elementsCount; + + /** Buffer resizing strategy. */ + protected final ArraySizingStrategy resizer; + + /** New instance with sane defaults. */ + public LongArrayList() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public LongArrayList(int expectedElements) { + this(expectedElements, DEFAULT_SIZING_STRATEGY); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public LongArrayList(int expectedElements, ArraySizingStrategy resizer) { + assert resizer != null; + this.resizer = resizer; + buffer = Arrays.copyOf(buffer, expectedElements); + } + + /** Creates a new list from the elements of another container in its iteration order. */ + public LongArrayList(LongContainer container) { + this(container.size()); + addAll(container); + } + + /** {@inheritDoc} */ + @Override + public void add(long e1) { + ensureBufferSpace(1); + buffer[elementsCount++] = e1; + } + + /** + * Appends two elements at the end of the list. To add more than two elements, use add + * (vararg-version) or access the buffer directly (tight loop). + */ + public void add(long e1, long e2) { + ensureBufferSpace(2); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + } + + /** Add all elements from a range of given array to the list. */ + public void add(long[] elements, int start, int length) { + assert length >= 0 : "Length must be >= 0"; + + ensureBufferSpace(length); + System.arraycopy(elements, start, buffer, elementsCount, length); + elementsCount += length; + } + + /** + * Vararg-signature method for adding elements at the end of the list. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + */ + public final void add(long... elements) { + add(elements, 0, elements.length); + } + + /** Adds all elements from another container. */ + public int addAll(LongContainer container) { + final int size = container.size(); + ensureBufferSpace(size); + + for (LongCursor cursor : container) { + add(cursor.value); + } + + return size; + } + + /** Adds all elements from another iterable. */ + public int addAll(Iterable iterable) { + int size = 0; + for (LongCursor cursor : iterable) { + add(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public void insert(int index, long e1) { + assert (index >= 0 && index <= size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + "]."; + + ensureBufferSpace(1); + System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index); + buffer[index] = e1; + elementsCount++; + } + + /** {@inheritDoc} */ + @Override + public long get(int index) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + return buffer[index]; + } + + /** {@inheritDoc} */ + @Override + public long set(int index, long e1) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + final long v = buffer[index]; + buffer[index] = e1; + return v; + } + + /** {@inheritDoc} */ + @Override + public long removeAt(int index) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + final long v = buffer[index]; + System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index); + + return v; + } + + /** {@inheritDoc} */ + @Override + public long removeLast() { + assert elementsCount > 0; + + final long v = buffer[--elementsCount]; + + return v; + } + + /** {@inheritDoc} */ + @Override + public void removeRange(int fromIndex, int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex); + final int count = toIndex - fromIndex; + elementsCount -= count; + } + + /** {@inheritDoc} */ + @Override + public boolean removeElement(long e1) { + return removeFirst(e1) != -1; + } + + /** {@inheritDoc} */ + @Override + public int removeFirst(long e1) { + final int index = indexOf(e1); + if (index >= 0) removeAt(index); + return index; + } + + /** {@inheritDoc} */ + @Override + public int removeLast(long e1) { + final int index = lastIndexOf(e1); + if (index >= 0) removeAt(index); + return index; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(long e1) { + int to = 0; + for (int from = 0; from < elementsCount; from++) { + if (((e1) == (buffer[from]))) { + continue; + } + if (to != from) { + buffer[to] = buffer[from]; + } + to++; + } + final int deleted = elementsCount - to; + this.elementsCount = to; + + return deleted; + } + + /** {@inheritDoc} */ + @Override + public boolean contains(long e1) { + return indexOf(e1) >= 0; + } + + /** {@inheritDoc} */ + @Override + public int indexOf(long e1) { + for (int i = 0; i < elementsCount; i++) { + if (((e1) == (buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int lastIndexOf(long e1) { + for (int i = elementsCount - 1; i >= 0; i--) { + if (((e1) == (buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return elementsCount == 0; + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + final int bufferLen = (buffer == null ? 0 : buffer.length); + if (expectedElements > bufferLen) { + ensureBufferSpace(expectedElements - size()); + } + } + + /** + * Ensures the internal buffer has enough free slots to store expectedAdditions. + * Increases internal buffer size if needed. + */ + protected void ensureBufferSpace(int expectedAdditions) { + final int bufferLen = (buffer == null ? 0 : buffer.length); + if (elementsCount + expectedAdditions > bufferLen) { + final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions); + assert newSize >= elementsCount + expectedAdditions + : "Resizer failed to" + + " return sensible new size: " + + newSize + + " <= " + + (elementsCount + expectedAdditions); + + this.buffer = Arrays.copyOf(buffer, newSize); + } + } + + /** + * Truncate or expand the list to the new size. If the list is truncated, the buffer will not be + * reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated + * values will be reset to the default value (zero). If the list is expanded, the elements beyond + * the current size are initialized with JVM-defaults (zero or null values). + */ + public void resize(int newSize) { + if (newSize <= buffer.length) { + if (newSize < elementsCount) { + Arrays.fill(buffer, newSize, elementsCount, 0L); + } else { + Arrays.fill(buffer, elementsCount, newSize, 0L); + } + } else { + ensureCapacity(newSize); + } + this.elementsCount = newSize; + } + + /** {@inheritDoc} */ + @Override + public int size() { + return elementsCount; + } + + /** Trim the internal buffer to the current size. */ + public void trimToSize() { + if (size() != this.buffer.length) { + this.buffer = toArray(); + } + } + + /** + * Sets the number of stored elements to zero. Releases and initializes the internal storage array + * to default values. To clear the list without cleaning the buffer, simply set the {@link + * #elementsCount} field to zero. + */ + @Override + public void clear() { + Arrays.fill(buffer, 0, elementsCount, 0L); + this.elementsCount = 0; + } + + /** Sets the number of stored elements to zero and releases the internal storage array. */ + @Override + public void release() { + this.buffer = EMPTY_ARRAY; + this.elementsCount = 0; + } + + /** + * {@inheritDoc} + * + *

The returned array is sized to match exactly the number of elements of the stack. + */ + @Override + public long[] toArray() { + + return Arrays.copyOf(buffer, elementsCount); + } + + @Override + public LongStream stream() { + + return Arrays.stream(buffer, 0, size()); + } + + /** {@inheritDoc} */ + @Override + public LongIndexedContainer sort() { + Arrays.sort(buffer, 0, elementsCount); + return this; + } + + /** {@inheritDoc} */ + @Override + public LongIndexedContainer reverse() { + for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) { + long tmp = buffer[i]; + buffer[i] = buffer[j]; + buffer[j] = tmp; + } + return this; + } + + /** + * Clone this object. The returned clone will reuse the same hash function and array resizing + * strategy. + */ + @Override + public LongArrayList clone() { + try { + + final LongArrayList cloned = (LongArrayList) super.clone(); + cloned.buffer = buffer.clone(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 1, max = elementsCount; + for (int i = 0; i < max; i++) { + h = 31 * h + BitMixer.mix(this.buffer[i]); + } + return h; + } + + /** + * Returns true only if the other object is an instance of the same class and with + * the same elements. + */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Compare index-aligned elements against another {@link LongIndexedContainer}. */ + protected boolean equalElements(LongArrayList other) { + int max = size(); + if (other.size() != max) { + return false; + } + + for (int i = 0; i < max; i++) { + if (!((get(i)) == (other.get(i)))) { + return false; + } + } + + return true; + } + + @Override + public long ramBytesAllocated() { + // int: elementsCount + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES + + resizer.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(buffer); + } + + @Override + public long ramBytesUsed() { + // int: elementsCount + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES + + resizer.ramBytesUsed() + + RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount); + } + + /** An iterator implementation for {@link LongArrayList#iterator}. */ + static final class ValueIterator extends AbstractIterator { + private final LongCursor cursor; + + private final long[] buffer; + private final int size; + + public ValueIterator(long[] buffer, int size) { + this.cursor = new LongCursor(); + this.cursor.index = -1; + this.size = size; + this.buffer = buffer; + } + + @Override + protected LongCursor fetch() { + if (cursor.index + 1 == size) return done(); + + cursor.value = buffer[++cursor.index]; + return cursor; + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new ValueIterator(buffer, size()); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + return forEach(procedure, 0, size()); + } + + /** + * Applies procedure to a slice of the list, fromIndex, inclusive, to + * toIndex, exclusive. + */ + public T forEach(T procedure, int fromIndex, final int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + final long[] buffer = this.buffer; + for (int i = fromIndex; i < toIndex; i++) { + procedure.apply(buffer[i]); + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongPredicate predicate) { + final long[] buffer = this.buffer; + final int elementsCount = this.elementsCount; + int to = 0; + int from = 0; + try { + for (; from < elementsCount; from++) { + if (predicate.apply(buffer[from])) { + buffer[from] = 0L; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0L; + } + to++; + } + } finally { + // Keep the list in a consistent state, even if the predicate throws an exception. + for (; from < elementsCount; from++) { + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = 0L; + } + to++; + } + + this.elementsCount = to; + } + + return elementsCount - to; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + return forEach(predicate, 0, size()); + } + + /** + * Applies predicate to a slice of the list, fromIndex, inclusive, to + * toIndex, exclusive, or until predicate returns false. + */ + public T forEach(T predicate, int fromIndex, final int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + final long[] buffer = this.buffer; + for (int i = fromIndex; i < toIndex; i++) { + if (!predicate.apply(buffer[i])) break; + } + + return predicate; + } + + /** + * Create a list from a variable number of arguments or an array of long. The + * elements are copied from the argument to the internal buffer. + */ + public static LongArrayList from(long... elements) { + final LongArrayList list = new LongArrayList(elements.length); + list.add(elements); + return list; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/LongBufferVisualizer.java b/src/main/java/com/carrotsearch/hppc/LongBufferVisualizer.java new file mode 100755 index 00000000..1c9e0af9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongBufferVisualizer.java @@ -0,0 +1,33 @@ +package com.carrotsearch.hppc; + +/** + * Reused buffer visualization routines. + * + * @see LongSet#visualizeKeyDistribution(int) + * @see LongVTypeMap#visualizeKeyDistribution(int) + */ +class LongBufferVisualizer { + static String visualizeKeyDistribution(long[] buffer, int max, int characters) { + final StringBuilder b = new StringBuilder(); + final char[] chars = ".123456789X".toCharArray(); + for (int i = 1, start = -1; i <= characters; i++) { + int end = (int) ((long) i * max / characters); + + if (start + 1 <= end) { + int taken = 0; + int slots = 0; + for (int slot = start + 1; slot <= end; slot++, slots++) { + if (!((buffer[slot]) == 0)) { + taken++; + } + } + b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]); + start = end; + } + } + while (b.length() < characters) { + b.append(' '); + } + return b.toString(); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/LongByteAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/LongByteAssociativeContainer.java new file mode 100755 index 00000000..b3e17bfa --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongByteAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see LongContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface LongByteAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(long key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongBytePredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link LongByteProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link LongBytePredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public LongCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public ByteContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongByteHashMap.java b/src/main/java/com/carrotsearch/hppc/LongByteHashMap.java new file mode 100755 index 00000000..eeaf5028 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongByteHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of long to byte, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeHashMap.java") +public class LongByteHashMap implements LongByteMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public long[] keys; + + /** The array holding values. */ + public byte[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public LongByteHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public LongByteHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public LongByteHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public LongByteHashMap(LongByteAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public byte put(long key, byte value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + byte previousValue = hasEmptyKey ? values[mask + 1] : ((byte) 0); + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final byte previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return ((byte) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(LongByteAssociativeContainer container) { + final int count = size(); + for (LongByteCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (LongByteCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public byte putOrAdd(long key, byte putValue, byte incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((byte) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public byte addTo(long key, byte incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public byte remove(long key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return ((byte) 0); + } + hasEmptyKey = false; + byte previousValue = values[mask + 1]; + values[mask + 1] = ((byte) 0); + return previousValue; + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final byte previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return ((byte) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof LongLookupContainer) { + if (hasEmptyKey && other.contains(0L)) { + hasEmptyKey = false; + values[mask + 1] = ((byte) 0); + } + + final long[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + long existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (LongCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongBytePredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(0L, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = ((byte) 0); + } + } + + final long[] keys = this.keys; + final byte[] values = this.values; + for (int slot = 0; slot <= mask; ) { + long existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(0L)) { + hasEmptyKey = false; + values[mask + 1] = ((byte) 0); + } + } + + final long[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + long existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public byte get(long key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : ((byte) 0); + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return ((byte) 0); + } + } + + /** {@inheritDoc} */ + @Override + public byte getOrDefault(long key, byte defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(long key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(long key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public byte indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public byte indexReplace(int index, byte newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + byte previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, long key, byte value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public byte indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + byte previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = ((byte) 0); + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, 0L); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (LongByteCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(LongByteHashMap other) { + if (other.size() != size()) { + return false; + } + + for (LongByteCursor c : other) { + long key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final long[] prevKeys = this.keys; + final byte[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final LongByteCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new LongByteCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongByteCursor fetch() { + final int mask = LongByteHashMap.this.mask; + while (index <= mask) { + long existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = 0L; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final long[] keys = this.keys; + final byte[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(0L, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final long[] keys = this.keys; + final byte[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(0L, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { + private final LongByteHashMap owner = LongByteHashMap.this; + + @Override + public boolean contains(long e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((LongByteProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((LongBytePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(LongPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final long e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final LongCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new LongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongCursor fetch() { + final int mask = LongByteHashMap.this.mask; + while (index <= mask) { + long existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = 0L; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public ByteCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractByteCollection { + private final LongByteHashMap owner = LongByteHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(byte value) { + for (LongByteCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (LongByteCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (LongByteCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final byte e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final BytePredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ByteCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new ByteCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ByteCursor fetch() { + final int mask = LongByteHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public LongByteHashMap clone() { + try { + + LongByteHashMap cloned = (LongByteHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (LongByteCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return LongBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static LongByteHashMap from(long[] keys, byte[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + LongByteHashMap map = new LongByteHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(long key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(long[] fromKeys, byte[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final long[] keys = this.keys; + final byte[] values = this.values; + final int mask = this.mask; + long existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + long[] prevKeys = this.keys; + byte[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new long[arraySize + emptyElementSlot]); + this.values = (new byte[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, long pendingKey, byte pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final long[] prevKeys = this.keys; + final byte[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final long[] keys = this.keys; + final byte[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final long existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = 0L; + values[gapSlot] = ((byte) 0); + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/LongByteMap.java b/src/main/java/com/carrotsearch/hppc/LongByteMap.java new file mode 100755 index 00000000..1291678d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongByteMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.LongByteCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface LongByteMap extends LongByteAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public byte get(long key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public byte getOrDefault(long key, byte defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public byte put(long key, byte value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(long key, byte value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(LongByteAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public byte putOrAdd(long key, byte putValue, byte incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public byte addTo(long key, byte additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public byte remove(long key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link LongByteMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(long key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public byte indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public byte indexReplace(int index, byte newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, long key, byte value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public byte indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongCharAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/LongCharAssociativeContainer.java new file mode 100755 index 00000000..9188f4e5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongCharAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see LongContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface LongCharAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(long key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongCharPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link LongCharProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link LongCharPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public LongCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public CharContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongCharHashMap.java b/src/main/java/com/carrotsearch/hppc/LongCharHashMap.java new file mode 100755 index 00000000..c5262ab9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongCharHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of long to char, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeHashMap.java") +public class LongCharHashMap implements LongCharMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public long[] keys; + + /** The array holding values. */ + public char[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public LongCharHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public LongCharHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public LongCharHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public LongCharHashMap(LongCharAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public char put(long key, char value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + char previousValue = hasEmptyKey ? values[mask + 1] : ((char) 0); + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final char previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return ((char) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(LongCharAssociativeContainer container) { + final int count = size(); + for (LongCharCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (LongCharCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public char putOrAdd(long key, char putValue, char incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((char) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public char addTo(long key, char incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public char remove(long key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return ((char) 0); + } + hasEmptyKey = false; + char previousValue = values[mask + 1]; + values[mask + 1] = ((char) 0); + return previousValue; + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final char previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return ((char) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof LongLookupContainer) { + if (hasEmptyKey && other.contains(0L)) { + hasEmptyKey = false; + values[mask + 1] = ((char) 0); + } + + final long[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + long existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (LongCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongCharPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(0L, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = ((char) 0); + } + } + + final long[] keys = this.keys; + final char[] values = this.values; + for (int slot = 0; slot <= mask; ) { + long existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(0L)) { + hasEmptyKey = false; + values[mask + 1] = ((char) 0); + } + } + + final long[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + long existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public char get(long key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : ((char) 0); + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return ((char) 0); + } + } + + /** {@inheritDoc} */ + @Override + public char getOrDefault(long key, char defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(long key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(long key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public char indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public char indexReplace(int index, char newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + char previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, long key, char value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public char indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + char previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = ((char) 0); + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, 0L); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (LongCharCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(LongCharHashMap other) { + if (other.size() != size()) { + return false; + } + + for (LongCharCursor c : other) { + long key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final long[] prevKeys = this.keys; + final char[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final LongCharCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new LongCharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongCharCursor fetch() { + final int mask = LongCharHashMap.this.mask; + while (index <= mask) { + long existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = 0L; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final long[] keys = this.keys; + final char[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(0L, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final long[] keys = this.keys; + final char[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(0L, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { + private final LongCharHashMap owner = LongCharHashMap.this; + + @Override + public boolean contains(long e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((LongCharProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((LongCharPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(LongPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final long e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final LongCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new LongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongCursor fetch() { + final int mask = LongCharHashMap.this.mask; + while (index <= mask) { + long existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = 0L; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public CharCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractCharCollection { + private final LongCharHashMap owner = LongCharHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(char value) { + for (LongCharCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (LongCharCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (LongCharCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final char e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final CharPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final CharCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new CharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharCursor fetch() { + final int mask = LongCharHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public LongCharHashMap clone() { + try { + + LongCharHashMap cloned = (LongCharHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (LongCharCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return LongBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static LongCharHashMap from(long[] keys, char[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + LongCharHashMap map = new LongCharHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(long key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(long[] fromKeys, char[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final long[] keys = this.keys; + final char[] values = this.values; + final int mask = this.mask; + long existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + long[] prevKeys = this.keys; + char[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new long[arraySize + emptyElementSlot]); + this.values = (new char[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, long pendingKey, char pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final long[] prevKeys = this.keys; + final char[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final long[] keys = this.keys; + final char[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final long existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = 0L; + values[gapSlot] = ((char) 0); + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/LongCharMap.java b/src/main/java/com/carrotsearch/hppc/LongCharMap.java new file mode 100755 index 00000000..fbc9d681 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongCharMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.LongCharCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface LongCharMap extends LongCharAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public char get(long key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public char getOrDefault(long key, char defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public char put(long key, char value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(long key, char value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(LongCharAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public char putOrAdd(long key, char putValue, char incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public char addTo(long key, char additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public char remove(long key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link LongCharMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(long key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public char indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public char indexReplace(int index, char newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, long key, char value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public char indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongCollection.java b/src/main/java/com/carrotsearch/hppc/LongCollection.java new file mode 100755 index 00000000..65869b85 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongCollection.java @@ -0,0 +1,64 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.predicates.LongPredicate; + +/** + * A collection allows basic, efficient operations on sets of elements (difference and + * intersection). + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java") +public interface LongCollection extends LongContainer { + /** + * Removes all occurrences of e from this collection. + * + * @param e Element to be removed from this collection, if present. + * @return The number of removed elements as a result of this call. + */ + public int removeAll(long e); + + /** + * Removes all elements in this collection that are present in c. + * + * @return Returns the number of removed elements. + */ + public int removeAll(LongLookupContainer c); + + /** + * Removes all elements in this collection for which the given predicate returns true + * . + * + * @return Returns the number of removed elements. + */ + public int removeAll(LongPredicate predicate); + + /** + * Keeps all elements in this collection that are present in c. Runs in time + * proportional to the number of elements in this collection. Equivalent of sets intersection. + * + * @return Returns the number of removed elements. + */ + public int retainAll(LongLookupContainer c); + + /** + * Keeps all elements in this collection for which the given predicate returns true. + * + * @return Returns the number of removed elements. + */ + public int retainAll(LongPredicate predicate); + + /** + * Removes all elements from this collection. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongContainer.java b/src/main/java/com/carrotsearch/hppc/LongContainer.java new file mode 100755 index 00000000..cc10b05a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongContainer.java @@ -0,0 +1,76 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.LongCursor; +import com.carrotsearch.hppc.predicates.LongPredicate; +import com.carrotsearch.hppc.procedures.LongProcedure; +import java.util.Iterator; + +/** A generic container holding longs. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java") +public interface LongContainer extends Iterable { + /** + * Returns an iterator to a cursor traversing the collection. The order of traversal is not + * defined. More than one cursor may be active at a time. The behavior of iterators is undefined + * if structural changes are made to the underlying collection. + * + *

The iterator is implemented as a cursor and it returns the same cursor instance on + * every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current + * list's value (or index in the list) use the cursor's public fields. An example is shown below. + * + *

+   * for (LongCursor<long> c : container) {
+   *   System.out.println("index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator iterator(); + + /** + * Lookup a given element in the container. This operation has no speed guarantees (may be linear + * with respect to the size of this container). + * + * @return Returns true if this container has an element equal to e. + */ + public boolean contains(long e); + + /** + * Return the current number of elements in this container. The time for calculating the + * container's size may take O(n) time, although implementing classes should try to + * maintain the current size and return in constant time. + */ + public int size(); + + /** Shortcut for size() == 0. */ + public boolean isEmpty(); + + /** + * Copies all elements of this container to an array. + * + *

The returned array is always a copy, regardless of the storage used by the container. + */ + public long[] toArray(); + + /** + * Applies a procedure to all container elements. Returns the argument (any subclass + * of {@link LongProcedure}. This lets the caller to call methods of the argument by chaining the + * call (even if the argument is an anonymous type) to retrieve computed values, for example + * (IntContainer): + * + *

+   * int count = container.forEach(new IntProcedure() {
+   *   int count; // this is a field declaration in an anonymous class.
+   *
+   *   public void apply(int value) {
+   *     count++;
+   *   }
+   * }).count;
+   * 
+ */ + public T forEach(T procedure); + + /** + * Applies a predicate to container elements as long, as the predicate returns + * true. The iteration is interrupted otherwise. + */ + public T forEach(T predicate); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongDeque.java b/src/main/java/com/carrotsearch/hppc/LongDeque.java new file mode 100755 index 00000000..a2a202b9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongDeque.java @@ -0,0 +1,77 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.LongCursor; +import com.carrotsearch.hppc.predicates.LongPredicate; +import com.carrotsearch.hppc.procedures.LongProcedure; +import java.util.Deque; +import java.util.Iterator; + +/** + * A linear collection that supports element insertion and removal at both ends. + * + * @see Deque + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java") +public interface LongDeque extends LongCollection { + /** + * Removes the first element that equals e. + * + * @return The deleted element's index or -1 if the element was not found. + */ + public int removeFirst(long e); + + /** + * Removes the last element that equals e. + * + * @return The deleted element's index or -1 if the element was not found. + */ + public int removeLast(long e); + + /** Inserts the specified element at the front of this deque. */ + public void addFirst(long e); + + /** Inserts the specified element at the end of this deque. */ + public void addLast(long e); + + /** + * Retrieves and removes the first element of this deque. + * + * @return the head (first) element of this deque. + */ + public long removeFirst(); + + /** + * Retrieves and removes the last element of this deque. + * + * @return the tail of this deque. + */ + public long removeLast(); + + /** + * Retrieves the first element of this deque but does not remove it. + * + * @return the head of this deque. + */ + public long getFirst(); + + /** + * Retrieves the last element of this deque but does not remove it. + * + * @return the head of this deque. + */ + public long getLast(); + + /** + * @return An iterator over elements in this deque in tail-to-head order. + */ + public Iterator descendingIterator(); + + /** Applies a procedure to all elements in tail-to-head order. */ + public T descendingForEach(T procedure); + + /** + * Applies a predicate to container elements as long, as the predicate returns + * true. The iteration is interrupted otherwise. + */ + public T descendingForEach(T predicate); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongDoubleAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/LongDoubleAssociativeContainer.java new file mode 100755 index 00000000..f0ec0558 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongDoubleAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see LongContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface LongDoubleAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *
+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(long key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongDoublePredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link LongDoubleProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link LongDoublePredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public LongCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public DoubleContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/LongDoubleHashMap.java new file mode 100755 index 00000000..2df0b5ab --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongDoubleHashMap.java @@ -0,0 +1,1082 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of long to double, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeHashMap.java") +public class LongDoubleHashMap implements LongDoubleMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public long[] keys; + + /** The array holding values. */ + public double[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public LongDoubleHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public LongDoubleHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public LongDoubleHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public LongDoubleHashMap(LongDoubleAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public double put(long key, double value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + double previousValue = hasEmptyKey ? values[mask + 1] : 0d; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final double previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0d; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(LongDoubleAssociativeContainer container) { + final int count = size(); + for (LongDoubleCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (LongDoubleCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public double putOrAdd(long key, double putValue, double incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((double) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public double addTo(long key, double incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public double remove(long key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return 0d; + } + hasEmptyKey = false; + double previousValue = values[mask + 1]; + values[mask + 1] = 0d; + return previousValue; + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final double previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0d; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof LongLookupContainer) { + if (hasEmptyKey && other.contains(0L)) { + hasEmptyKey = false; + values[mask + 1] = 0d; + } + + final long[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + long existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (LongCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongDoublePredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(0L, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0d; + } + } + + final long[] keys = this.keys; + final double[] values = this.values; + for (int slot = 0; slot <= mask; ) { + long existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(0L)) { + hasEmptyKey = false; + values[mask + 1] = 0d; + } + } + + final long[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + long existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public double get(long key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : 0d; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0d; + } + } + + /** {@inheritDoc} */ + @Override + public double getOrDefault(long key, double defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(long key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(long key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public double indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public double indexReplace(int index, double newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + double previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, long key, double value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public double indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + double previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0d; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, 0L); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (LongDoubleCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(LongDoubleHashMap other) { + if (other.size() != size()) { + return false; + } + + for (LongDoubleCursor c : other) { + long key = c.key; + if (!containsKey(key) + || !(Double.doubleToLongBits(c.value) == Double.doubleToLongBits(get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final long[] prevKeys = this.keys; + final double[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final LongDoubleCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new LongDoubleCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongDoubleCursor fetch() { + final int mask = LongDoubleHashMap.this.mask; + while (index <= mask) { + long existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = 0L; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final long[] keys = this.keys; + final double[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(0L, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final long[] keys = this.keys; + final double[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(0L, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { + private final LongDoubleHashMap owner = LongDoubleHashMap.this; + + @Override + public boolean contains(long e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((LongDoubleProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((LongDoublePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(LongPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final long e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final LongCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new LongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongCursor fetch() { + final int mask = LongDoubleHashMap.this.mask; + while (index <= mask) { + long existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = 0L; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public DoubleCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractDoubleCollection { + private final LongDoubleHashMap owner = LongDoubleHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(double value) { + for (LongDoubleCursor c : owner) { + if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (LongDoubleCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (LongDoubleCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final double e) { + return owner.removeAll( + (key, value) -> (Double.doubleToLongBits(e) == Double.doubleToLongBits(value))); + } + + @Override + public int removeAll(final DoublePredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final DoubleCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new DoubleCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected DoubleCursor fetch() { + final int mask = LongDoubleHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public LongDoubleHashMap clone() { + try { + + LongDoubleHashMap cloned = (LongDoubleHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (LongDoubleCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return LongBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static LongDoubleHashMap from(long[] keys, double[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + LongDoubleHashMap map = new LongDoubleHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(long key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(long[] fromKeys, double[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final long[] keys = this.keys; + final double[] values = this.values; + final int mask = this.mask; + long existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + long[] prevKeys = this.keys; + double[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new long[arraySize + emptyElementSlot]); + this.values = (new double[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, long pendingKey, double pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final long[] prevKeys = this.keys; + final double[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final long[] keys = this.keys; + final double[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final long existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = 0L; + values[gapSlot] = 0d; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/LongDoubleMap.java b/src/main/java/com/carrotsearch/hppc/LongDoubleMap.java new file mode 100755 index 00000000..7c83d309 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongDoubleMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.LongDoubleCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface LongDoubleMap extends LongDoubleAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public double get(long key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public double getOrDefault(long key, double defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public double put(long key, double value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(long key, double value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(LongDoubleAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public double putOrAdd(long key, double putValue, double incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public double addTo(long key, double additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public double remove(long key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link LongDoubleMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(long key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public double indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public double indexReplace(int index, double newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, long key, double value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public double indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongFloatAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/LongFloatAssociativeContainer.java new file mode 100755 index 00000000..80cc2da1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongFloatAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see LongContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface LongFloatAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(long key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongFloatPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link LongFloatProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link LongFloatPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public LongCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public FloatContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/LongFloatHashMap.java new file mode 100755 index 00000000..bc0d5f2d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongFloatHashMap.java @@ -0,0 +1,1081 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of long to float, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeHashMap.java") +public class LongFloatHashMap implements LongFloatMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public long[] keys; + + /** The array holding values. */ + public float[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public LongFloatHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public LongFloatHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public LongFloatHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public LongFloatHashMap(LongFloatAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public float put(long key, float value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + float previousValue = hasEmptyKey ? values[mask + 1] : 0f; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final float previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0f; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(LongFloatAssociativeContainer container) { + final int count = size(); + for (LongFloatCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (LongFloatCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public float putOrAdd(long key, float putValue, float incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((float) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public float addTo(long key, float incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public float remove(long key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return 0f; + } + hasEmptyKey = false; + float previousValue = values[mask + 1]; + values[mask + 1] = 0f; + return previousValue; + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final float previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0f; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof LongLookupContainer) { + if (hasEmptyKey && other.contains(0L)) { + hasEmptyKey = false; + values[mask + 1] = 0f; + } + + final long[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + long existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (LongCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongFloatPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(0L, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0f; + } + } + + final long[] keys = this.keys; + final float[] values = this.values; + for (int slot = 0; slot <= mask; ) { + long existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(0L)) { + hasEmptyKey = false; + values[mask + 1] = 0f; + } + } + + final long[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + long existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public float get(long key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : 0f; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0f; + } + } + + /** {@inheritDoc} */ + @Override + public float getOrDefault(long key, float defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(long key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(long key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public float indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public float indexReplace(int index, float newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + float previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, long key, float value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public float indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + float previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0f; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, 0L); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (LongFloatCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(LongFloatHashMap other) { + if (other.size() != size()) { + return false; + } + + for (LongFloatCursor c : other) { + long key = c.key; + if (!containsKey(key) || !(Float.floatToIntBits(c.value) == Float.floatToIntBits(get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final long[] prevKeys = this.keys; + final float[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final LongFloatCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new LongFloatCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongFloatCursor fetch() { + final int mask = LongFloatHashMap.this.mask; + while (index <= mask) { + long existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = 0L; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final long[] keys = this.keys; + final float[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(0L, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final long[] keys = this.keys; + final float[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(0L, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { + private final LongFloatHashMap owner = LongFloatHashMap.this; + + @Override + public boolean contains(long e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((LongFloatProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((LongFloatPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(LongPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final long e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final LongCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new LongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongCursor fetch() { + final int mask = LongFloatHashMap.this.mask; + while (index <= mask) { + long existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = 0L; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public FloatCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractFloatCollection { + private final LongFloatHashMap owner = LongFloatHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(float value) { + for (LongFloatCursor c : owner) { + if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (LongFloatCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (LongFloatCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final float e) { + return owner.removeAll( + (key, value) -> (Float.floatToIntBits(e) == Float.floatToIntBits(value))); + } + + @Override + public int removeAll(final FloatPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final FloatCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new FloatCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected FloatCursor fetch() { + final int mask = LongFloatHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public LongFloatHashMap clone() { + try { + + LongFloatHashMap cloned = (LongFloatHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (LongFloatCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return LongBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static LongFloatHashMap from(long[] keys, float[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + LongFloatHashMap map = new LongFloatHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(long key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(long[] fromKeys, float[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final long[] keys = this.keys; + final float[] values = this.values; + final int mask = this.mask; + long existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + long[] prevKeys = this.keys; + float[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new long[arraySize + emptyElementSlot]); + this.values = (new float[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, long pendingKey, float pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final long[] prevKeys = this.keys; + final float[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final long[] keys = this.keys; + final float[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final long existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = 0L; + values[gapSlot] = 0f; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/LongFloatMap.java b/src/main/java/com/carrotsearch/hppc/LongFloatMap.java new file mode 100755 index 00000000..dc4cf199 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongFloatMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.LongFloatCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface LongFloatMap extends LongFloatAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public float get(long key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public float getOrDefault(long key, float defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public float put(long key, float value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(long key, float value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(LongFloatAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public float putOrAdd(long key, float putValue, float incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public float addTo(long key, float additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public float remove(long key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link LongFloatMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(long key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public float indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public float indexReplace(int index, float newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, long key, float value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public float indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongHashSet.java b/src/main/java/com/carrotsearch/hppc/LongHashSet.java new file mode 100755 index 00000000..8957939d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongHashSet.java @@ -0,0 +1,787 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash set of longs, implemented using open addressing with linear probing for + * collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeHashSet.java") +public class LongHashSet extends AbstractLongCollection + implements LongLookupContainer, LongSet, Preallocable, Cloneable, Accountable { + /** The hash array holding keys. */ + public long[] keys; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any. + * + * @see #size() + * @see #hasEmptyKey + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** + * New instance with sane defaults. + * + * @see #LongHashSet(int, double) + */ + public LongHashSet() { + this(DEFAULT_EXPECTED_ELEMENTS, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with sane defaults. + * + * @see #LongHashSet(int, double) + */ + public LongHashSet(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public LongHashSet(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** New instance copying elements from another {@link LongContainer}. */ + public LongHashSet(LongContainer container) { + this(container.size()); + addAll(container); + } + + /** {@inheritDoc} */ + @Override + public boolean add(long key) { + if (((key) == 0)) { + assert ((keys[mask + 1]) == 0); + boolean added = !hasEmptyKey; + hasEmptyKey = true; + return added; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return false; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key); + } else { + keys[slot] = key; + } + + assigned++; + return true; + } + } + + /** + * Adds all elements from the given list (vararg) to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + */ + public final int addAll(long... elements) { + ensureCapacity(elements.length); + int count = 0; + for (long e : elements) { + if (add(e)) { + count++; + } + } + return count; + } + + /** + * Adds all elements from the given {@link LongContainer} to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + */ + public int addAll(LongContainer container) { + ensureCapacity(container.size()); + return addAll((Iterable) container); + } + + /** + * Adds all elements from the given iterable to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + */ + public int addAll(Iterable iterable) { + int count = 0; + for (LongCursor cursor : iterable) { + if (add(cursor.value)) { + count++; + } + } + return count; + } + + /** {@inheritDoc} */ + @Override + public long[] toArray() { + + final long[] cloned = (new long[size()]); + int j = 0; + if (hasEmptyKey) { + cloned[j++] = 0L; + } + + final long[] keys = this.keys; + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + long existing; + if (!((existing = keys[slot]) == 0)) { + cloned[j++] = existing; + } + } + + return cloned; + } + + /** An alias for the (preferred) {@link #removeAll}. */ + public boolean remove(long key) { + if (((key) == 0)) { + boolean hadEmptyKey = hasEmptyKey; + hasEmptyKey = false; + return hadEmptyKey; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + shiftConflictingKeys(slot); + return true; + } + slot = (slot + 1) & mask; + } + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(long key) { + return remove(key) ? 1 : 0; + } + + /** + * Removes all keys present in a given container. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongContainer other) { + final int before = size(); + + // Try to iterate over the smaller set or over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof LongLookupContainer) { + if (hasEmptyKey && other.contains(0L)) { + hasEmptyKey = false; + } + + final long[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + long existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (LongCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongPredicate predicate) { + int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(0L)) { + hasEmptyKey = false; + } + } + + final long[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + long existing; + if (!((existing = keys[slot]) == 0)) { + if (predicate.apply(existing)) { + shiftConflictingKeys(slot); + continue; // Repeat the check for the same slot i (shifted). + } + } + slot++; + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public boolean contains(long key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + return false; + } + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + Arrays.fill(keys, 0L); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + keys = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return size() == 0; + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final long[] prevKeys = this.keys; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys); + } + } + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + final long[] keys = this.keys; + for (int slot = mask; slot >= 0; slot--) { + long existing; + if (!((existing = keys[slot]) == 0)) { + h += BitMixer.mix(existing); + } + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && sameKeys(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + private boolean sameKeys(LongSet other) { + if (other.size() != size()) { + return false; + } + + for (LongCursor c : other) { + if (!contains(c.value)) { + return false; + } + } + + return true; + } + + /** {@inheritDoc} */ + @Override + public LongHashSet clone() { + try { + + LongHashSet cloned = (LongHashSet) super.clone(); + cloned.keys = keys.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + @Override + public long ramBytesAllocated() { + // int: assigned, mask, keyMixer, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys); + } + + @Override + public long ramBytesUsed() { + // int: assigned, mask, keyMixer, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + protected final class EntryIterator extends AbstractIterator { + private final LongCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new LongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongCursor fetch() { + final int mask = LongHashSet.this.mask; + while (index <= mask) { + long existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = 0L; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + if (hasEmptyKey) { + procedure.apply(0L); + } + + final long[] keys = this.keys; + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + long existing; + if (!((existing = keys[slot]) == 0)) { + procedure.apply(existing); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + if (hasEmptyKey) { + if (!predicate.apply(0L)) { + return predicate; + } + } + + final long[] keys = this.keys; + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + long existing; + if (!((existing = keys[slot]) == 0)) { + if (!predicate.apply(existing)) { + break; + } + } + } + + return predicate; + } + + /** + * Create a set from a variable number of arguments or an array of long. The elements + * are copied from the argument to the internal buffer. + */ + public static LongHashSet from(long... elements) { + final LongHashSet set = new LongHashSet(elements.length); + set.addAll(elements); + return set; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(long key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up logic in + * certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between modifications (it will not be affected by read-only + * operations). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the set. + * @return A non-negative value of the logical "index" of the key in the set or a negative value + * if the key did not exist. + */ + public int indexOf(long key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index) { + assert index < 0 || index <= mask || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** + * Returns the exact value of the existing key. This method makes sense for sets of objects which + * define custom key-equality relationship. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the equivalent key currently stored in the set. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public long indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return keys[index]; + } + + /** + * Replaces the existing equivalent key with the given one and returns any previous value stored + * for that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @param equivalentKey The key to put in the set as a replacement. Must be equivalent to the key + * currently stored at the provided index. + * @return Returns the previous key stored in the set. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public long indexReplace(int index, long equivalentKey) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + assert ((keys[index]) == (equivalentKey)); + + long previousValue = keys[index]; + keys[index] = equivalentKey; + return previousValue; + } + + /** + * Inserts a key for an index that is not present in the set. This method may help in avoiding + * double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public void indexInsert(int index, long key) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + assert ((keys[index]) == 0); + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key); + } else { + keys[index] = key; + } + + assigned++; + } + } + + /** + * Removes a key at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public void indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + if (index > mask) { + hasEmptyKey = false; + } else { + shiftConflictingKeys(index); + } + } + + @Override + public String visualizeKeyDistribution(int characters) { + return LongBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(long[] fromKeys) { + assert HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored keys into the new buffers. + final long[] keys = this.keys; + final int mask = this.mask; + long existing; + for (int i = fromKeys.length - 1; --i >= 0; ) { + if (!((existing = fromKeys[i]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + long[] prevKeys = this.keys; + try { + int emptyElementSlot = 1; + this.keys = (new long[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.keys == null ? 0 : size(), arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key to be inserted into the buffer but there is not + * enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, long pendingKey) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final long[] prevKeys = this.keys; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + + // Rehash old keys, including the pending key. + rehash(prevKeys); + } + + /** Shift all the slot-conflicting keys allocated to (and including) slot. */ + protected void shiftConflictingKeys(int gapSlot) { + final long[] keys = this.keys; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final long existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = 0L; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/LongIndexedContainer.java b/src/main/java/com/carrotsearch/hppc/LongIndexedContainer.java new file mode 100755 index 00000000..ba0c78a2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongIndexedContainer.java @@ -0,0 +1,93 @@ +package com.carrotsearch.hppc; + +import java.util.RandomAccess; +import java.util.stream.LongStream; + +/** + * An indexed container provides random access to elements based on an index. Indexes + * are zero-based. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeIndexedContainer.java") +public interface LongIndexedContainer extends LongCollection, RandomAccess { + /** + * Removes the first element that equals e1, returning whether an element has been + * removed. + */ + public boolean removeElement(long e1); + + /** + * Removes the first element that equals e1, returning its deleted position or + * -1 if the element was not found. + */ + public int removeFirst(long e1); + + /** + * Removes the last element that equals e1, returning its deleted position or + * -1 if the element was not found. + */ + public int removeLast(long e1); + + /** + * Returns the index of the first occurrence of the specified element in this list, or -1 if this + * list does not contain the element. + */ + public int indexOf(long e1); + + /** + * Returns the index of the last occurrence of the specified element in this list, or -1 if this + * list does not contain the element. + */ + public int lastIndexOf(long e1); + + /** Adds an element to the end of this container (the last index is incremented by one). */ + public void add(long e1); + + /** + * Inserts the specified element at the specified position in this list. + * + * @param index The index at which the element should be inserted, shifting any existing and + * subsequent elements to the right. + */ + public void insert(int index, long e1); + + /** + * Replaces the element at the specified position in this list with the specified element. + * + * @return Returns the previous value in the list. + */ + public long set(int index, long e1); + + /** + * @return Returns the element at index index from the list. + */ + public long get(int index); + + /** + * Removes the element at the specified position in this container and returns it. + * + * @see #removeFirst + * @see #removeLast + * @see #removeAll + */ + public long removeAt(int index); + + /** Removes and returns the last element of this container. This container must not be empty. */ + public long removeLast(); + + /** + * Removes from this container all of the elements with indexes between fromIndex, + * inclusive, and toIndex, exclusive. + */ + public void removeRange(int fromIndex, int toIndex); + + /** Returns this container elements as a stream. */ + public LongStream stream(); + + /** Sorts the elements in this container and returns this container. */ + public LongIndexedContainer sort(); + + /** Reverses the elements in this container and returns this container. */ + public LongIndexedContainer reverse(); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongIntAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/LongIntAssociativeContainer.java new file mode 100755 index 00000000..97467873 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongIntAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see LongContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface LongIntAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(long key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongIntPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link LongIntProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link LongIntPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public LongCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public IntContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongIntHashMap.java b/src/main/java/com/carrotsearch/hppc/LongIntHashMap.java new file mode 100755 index 00000000..de4d34b4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongIntHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of long to int, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeHashMap.java") +public class LongIntHashMap implements LongIntMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public long[] keys; + + /** The array holding values. */ + public int[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public LongIntHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public LongIntHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public LongIntHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public LongIntHashMap(LongIntAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public int put(long key, int value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + int previousValue = hasEmptyKey ? values[mask + 1] : 0; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final int previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(LongIntAssociativeContainer container) { + final int count = size(); + for (LongIntCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (LongIntCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public int putOrAdd(long key, int putValue, int incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((int) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public int addTo(long key, int incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public int remove(long key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return 0; + } + hasEmptyKey = false; + int previousValue = values[mask + 1]; + values[mask + 1] = 0; + return previousValue; + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final int previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof LongLookupContainer) { + if (hasEmptyKey && other.contains(0L)) { + hasEmptyKey = false; + values[mask + 1] = 0; + } + + final long[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + long existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (LongCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongIntPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(0L, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0; + } + } + + final long[] keys = this.keys; + final int[] values = this.values; + for (int slot = 0; slot <= mask; ) { + long existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(0L)) { + hasEmptyKey = false; + values[mask + 1] = 0; + } + } + + final long[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + long existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int get(long key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : 0; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0; + } + } + + /** {@inheritDoc} */ + @Override + public int getOrDefault(long key, int defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(long key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(long key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public int indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public int indexReplace(int index, int newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + int previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, long key, int value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public int indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + int previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, 0L); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (LongIntCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(LongIntHashMap other) { + if (other.size() != size()) { + return false; + } + + for (LongIntCursor c : other) { + long key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final long[] prevKeys = this.keys; + final int[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final LongIntCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new LongIntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongIntCursor fetch() { + final int mask = LongIntHashMap.this.mask; + while (index <= mask) { + long existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = 0L; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final long[] keys = this.keys; + final int[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(0L, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final long[] keys = this.keys; + final int[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(0L, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { + private final LongIntHashMap owner = LongIntHashMap.this; + + @Override + public boolean contains(long e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((LongIntProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((LongIntPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(LongPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final long e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final LongCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new LongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongCursor fetch() { + final int mask = LongIntHashMap.this.mask; + while (index <= mask) { + long existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = 0L; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public IntCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractIntCollection { + private final LongIntHashMap owner = LongIntHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(int value) { + for (LongIntCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (LongIntCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (LongIntCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final int e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final IntPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final IntCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new IntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntCursor fetch() { + final int mask = LongIntHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public LongIntHashMap clone() { + try { + + LongIntHashMap cloned = (LongIntHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (LongIntCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return LongBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static LongIntHashMap from(long[] keys, int[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + LongIntHashMap map = new LongIntHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(long key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(long[] fromKeys, int[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final long[] keys = this.keys; + final int[] values = this.values; + final int mask = this.mask; + long existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + long[] prevKeys = this.keys; + int[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new long[arraySize + emptyElementSlot]); + this.values = (new int[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, long pendingKey, int pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final long[] prevKeys = this.keys; + final int[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final long[] keys = this.keys; + final int[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final long existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = 0L; + values[gapSlot] = 0; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/LongIntMap.java b/src/main/java/com/carrotsearch/hppc/LongIntMap.java new file mode 100755 index 00000000..6fb8c866 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongIntMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.LongIntCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface LongIntMap extends LongIntAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public int get(long key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public int getOrDefault(long key, int defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public int put(long key, int value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(long key, int value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(LongIntAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public int putOrAdd(long key, int putValue, int incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public int addTo(long key, int additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public int remove(long key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link LongIntMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(long key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public int indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public int indexReplace(int index, int newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, long key, int value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public int indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongLongAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/LongLongAssociativeContainer.java new file mode 100755 index 00000000..24be1a2e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongLongAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see LongContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface LongLongAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(long key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongLongPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link LongLongProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link LongLongPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public LongCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public LongContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongLongHashMap.java b/src/main/java/com/carrotsearch/hppc/LongLongHashMap.java new file mode 100755 index 00000000..c1937803 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongLongHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of long to long, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeHashMap.java") +public class LongLongHashMap implements LongLongMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public long[] keys; + + /** The array holding values. */ + public long[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public LongLongHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public LongLongHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public LongLongHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public LongLongHashMap(LongLongAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public long put(long key, long value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + long previousValue = hasEmptyKey ? values[mask + 1] : 0L; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final long previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0L; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(LongLongAssociativeContainer container) { + final int count = size(); + for (LongLongCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (LongLongCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public long putOrAdd(long key, long putValue, long incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((long) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public long addTo(long key, long incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public long remove(long key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return 0L; + } + hasEmptyKey = false; + long previousValue = values[mask + 1]; + values[mask + 1] = 0L; + return previousValue; + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final long previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0L; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof LongLookupContainer) { + if (hasEmptyKey && other.contains(0L)) { + hasEmptyKey = false; + values[mask + 1] = 0L; + } + + final long[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + long existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (LongCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongLongPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(0L, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0L; + } + } + + final long[] keys = this.keys; + final long[] values = this.values; + for (int slot = 0; slot <= mask; ) { + long existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(0L)) { + hasEmptyKey = false; + values[mask + 1] = 0L; + } + } + + final long[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + long existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public long get(long key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : 0L; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0L; + } + } + + /** {@inheritDoc} */ + @Override + public long getOrDefault(long key, long defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(long key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(long key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public long indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public long indexReplace(int index, long newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + long previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, long key, long value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public long indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + long previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0L; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, 0L); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (LongLongCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(LongLongHashMap other) { + if (other.size() != size()) { + return false; + } + + for (LongLongCursor c : other) { + long key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final long[] prevKeys = this.keys; + final long[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final LongLongCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new LongLongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongLongCursor fetch() { + final int mask = LongLongHashMap.this.mask; + while (index <= mask) { + long existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = 0L; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final long[] keys = this.keys; + final long[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(0L, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final long[] keys = this.keys; + final long[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(0L, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { + private final LongLongHashMap owner = LongLongHashMap.this; + + @Override + public boolean contains(long e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((LongLongProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((LongLongPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(LongPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final long e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final LongCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new LongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongCursor fetch() { + final int mask = LongLongHashMap.this.mask; + while (index <= mask) { + long existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = 0L; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public LongCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractLongCollection { + private final LongLongHashMap owner = LongLongHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(long value) { + for (LongLongCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (LongLongCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (LongLongCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final long e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final LongPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final LongCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new LongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongCursor fetch() { + final int mask = LongLongHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public LongLongHashMap clone() { + try { + + LongLongHashMap cloned = (LongLongHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (LongLongCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return LongBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static LongLongHashMap from(long[] keys, long[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + LongLongHashMap map = new LongLongHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(long key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(long[] fromKeys, long[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final long[] keys = this.keys; + final long[] values = this.values; + final int mask = this.mask; + long existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + long[] prevKeys = this.keys; + long[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new long[arraySize + emptyElementSlot]); + this.values = (new long[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, long pendingKey, long pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final long[] prevKeys = this.keys; + final long[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final long[] keys = this.keys; + final long[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final long existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = 0L; + values[gapSlot] = 0L; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/LongLongMap.java b/src/main/java/com/carrotsearch/hppc/LongLongMap.java new file mode 100755 index 00000000..3ea093c9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongLongMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.LongLongCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface LongLongMap extends LongLongAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public long get(long key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public long getOrDefault(long key, long defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public long put(long key, long value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(long key, long value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(LongLongAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public long putOrAdd(long key, long putValue, long incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public long addTo(long key, long additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public long remove(long key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link LongLongMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(long key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public long indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public long indexReplace(int index, long newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, long key, long value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public long indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongLookupContainer.java b/src/main/java/com/carrotsearch/hppc/LongLookupContainer.java new file mode 100755 index 00000000..70a99942 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongLookupContainer.java @@ -0,0 +1,12 @@ +package com.carrotsearch.hppc; + +/** + * Marker interface for containers that can check if they contain a given object in at least time + * O(log n) and ideally in amortized constant time O(1). + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeLookupContainer.java") +public interface LongLookupContainer extends LongContainer { + public boolean contains(long e); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongObjectAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/LongObjectAssociativeContainer.java new file mode 100755 index 00000000..9e805ffc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongObjectAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see LongContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface LongObjectAssociativeContainer extends Iterable> { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator> iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(long key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongObjectPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link LongObjectProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public > T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link LongObjectPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public > T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public LongCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public ObjectContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/LongObjectHashMap.java new file mode 100755 index 00000000..e8647afd --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongObjectHashMap.java @@ -0,0 +1,1050 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of long to Object, implemented using open addressing with + * linear probing for collision resolution. Supports null values. + * + * @see HPPC interfaces diagram + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeHashMap.java") +public class LongObjectHashMap + implements LongObjectMap, Preallocable, Cloneable, Accountable { + /** The array holding keys. */ + public long[] keys; + + /** The array holding values. */ + public Object[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public LongObjectHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public LongObjectHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public LongObjectHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public LongObjectHashMap(LongObjectAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public VType put(long key, VType value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + VType previousValue = hasEmptyKey ? (VType) values[mask + 1] : null; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final VType previousValue = (VType) values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return null; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(LongObjectAssociativeContainer container) { + final int count = size(); + for (LongObjectCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable> iterable) { + final int count = size(); + for (LongObjectCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** {@inheritDoc} */ + @Override + public VType remove(long key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return null; + } + hasEmptyKey = false; + VType previousValue = (VType) values[mask + 1]; + values[mask + 1] = null; + return previousValue; + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final VType previousValue = (VType) values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return null; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof LongLookupContainer) { + if (hasEmptyKey && other.contains(0L)) { + hasEmptyKey = false; + values[mask + 1] = null; + } + + final long[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + long existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (LongCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongObjectPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(0L, (VType) values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = null; + } + } + + final long[] keys = this.keys; + final VType[] values = (VType[]) this.values; + for (int slot = 0; slot <= mask; ) { + long existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(0L)) { + hasEmptyKey = false; + values[mask + 1] = null; + } + } + + final long[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + long existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public VType get(long key) { + if (((key) == 0)) { + return hasEmptyKey ? (VType) values[mask + 1] : null; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return (VType) values[slot]; + } + slot = (slot + 1) & mask; + } + + return null; + } + } + + /** {@inheritDoc} */ + @Override + public VType getOrDefault(long key, VType defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? (VType) values[mask + 1] : defaultValue; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return (VType) values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(long key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(long key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public VType indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return (VType) values[index]; + } + + /** {@inheritDoc} */ + @Override + public VType indexReplace(int index, VType newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + VType previousValue = (VType) values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, long key, VType value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public VType indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + VType previousValue = (VType) values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = null; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, 0L); + + Arrays.fill(values, null); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (LongObjectCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** + * Return true if all keys of some other container exist in this container. Values are compared + * using {@link Objects#equals(Object)} method. + */ + protected boolean equalElements(LongObjectHashMap other) { + if (other.size() != size()) { + return false; + } + + for (LongObjectCursor c : other) { + long key = c.key; + if (!containsKey(key) || !java.util.Objects.equals(c.value, get(key))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final long[] prevKeys = this.keys; + final VType[] prevValues = (VType[]) this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final LongObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new LongObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongObjectCursor fetch() { + final int mask = LongObjectHashMap.this.mask; + while (index <= mask) { + long existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = (VType) values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = 0L; + cursor.value = (VType) values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator> iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T procedure) { + final long[] keys = this.keys; + final VType[] values = (VType[]) this.values; + + if (hasEmptyKey) { + procedure.apply(0L, (VType) values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T predicate) { + final long[] keys = this.keys; + final VType[] values = (VType[]) this.values; + + if (hasEmptyKey) { + if (!predicate.apply(0L, (VType) values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { + private final LongObjectHashMap owner = LongObjectHashMap.this; + + @Override + public boolean contains(long e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((LongObjectProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((LongObjectPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(LongPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final long e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final LongCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new LongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongCursor fetch() { + final int mask = LongObjectHashMap.this.mask; + while (index <= mask) { + long existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = 0L; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public ObjectCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractObjectCollection { + private final LongObjectHashMap owner = LongObjectHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(VType value) { + for (LongObjectCursor c : owner) { + if (java.util.Objects.equals(value, c.value)) { + return true; + } + } + return false; + } + + @Override + public > T forEach(T procedure) { + for (LongObjectCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public > T forEach(T predicate) { + for (LongObjectCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator> iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final VType e) { + return owner.removeAll((key, value) -> java.util.Objects.equals(e, value)); + } + + @Override + public int removeAll(final ObjectPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator> { + private final ObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new ObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectCursor fetch() { + final int mask = LongObjectHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = (VType) values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = (VType) values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public LongObjectHashMap clone() { + try { + + LongObjectHashMap cloned = (LongObjectHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (LongObjectCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return LongBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static LongObjectHashMap from(long[] keys, VType[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + LongObjectHashMap map = new LongObjectHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(long key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(long[] fromKeys, VType[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final long[] keys = this.keys; + final VType[] values = (VType[]) this.values; + final int mask = this.mask; + long existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + long[] prevKeys = this.keys; + VType[] prevValues = (VType[]) this.values; + try { + int emptyElementSlot = 1; + this.keys = (new long[arraySize + emptyElementSlot]); + this.values = ((VType[]) new Object[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, long pendingKey, VType pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final long[] prevKeys = this.keys; + final VType[] prevValues = (VType[]) this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final long[] keys = this.keys; + final VType[] values = (VType[]) this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final long existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = 0L; + values[gapSlot] = null; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/LongObjectMap.java b/src/main/java/com/carrotsearch/hppc/LongObjectMap.java new file mode 100755 index 00000000..712d01a5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongObjectMap.java @@ -0,0 +1,181 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.LongObjectCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface LongObjectMap extends LongObjectAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public VType get(long key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public VType getOrDefault(long key, VType defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public VType put(long key, VType value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(long key, VType value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(LongObjectAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable> iterable); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public VType remove(long key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link LongObjectMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(long key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public VType indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public VType indexReplace(int index, VType newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, long key, VType value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public VType indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongPgmIndex.java b/src/main/java/com/carrotsearch/hppc/LongPgmIndex.java new file mode 100755 index 00000000..dc80b159 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongPgmIndex.java @@ -0,0 +1,600 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.LongCursor; +import com.carrotsearch.hppc.procedures.LongProcedure; +import java.util.Arrays; +import java.util.Iterator; + +/** + * Space-efficient index that enables fast rank/range search operations on a sorted sequence of + * long. + * + *

Implementation of the PGM-Index described at https://pgm.di.unipi.it/, based on the paper + * + *

+ *   Paolo Ferragina and Giorgio Vinciguerra.
+ *   The PGM-index: a fully-dynamic compressed learned index with provable worst-case bounds.
+ *   PVLDB, 13(8): 1162-1175, 2020.
+ * 
+ * + * It provides {@code rank} and {@code range} search operations. {@code indexOf()} is faster than + * B+Tree, and the index is much more compact. {@code contains()} is between 4x to 7x slower than + * {@code IntHashSet#contains()}, but between 2.5x to 3x faster than {@link Arrays#binarySearch}. + * + *

Its compactness (40KB for 200MB of keys) makes it efficient for very large collections, the + * index fitting easily in the L2 cache. The {@code epsilon} parameter should be set according to + * the desired space-time trade-off. A smaller value makes the estimation more precise and the range + * smaller but at the cost of increased space usage. In practice, {@code epsilon} 64 is a good sweet + * spot. + * + *

Internally the index uses an optimal piecewise linear mapping from keys to their position in + * the sorted order. This mapping is represented as a sequence of linear models (segments) which are + * themselves recursively indexed by other piecewise linear mappings. + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypePgmIndex.java") +public class LongPgmIndex implements Accountable { + + /** Empty immutable LongPgmIndex. */ + public static final LongPgmIndex EMPTY = new LongEmptyPgmIndex(); + + /** + * Epsilon approximation range when searching the list of keys. Controls the size of the returned + * search range, strictly greater than 0. It should be set according to the desired space-time + * trade-off. A smaller value makes the estimation more precise and the range smaller but at the + * cost of increased space usage. + * + *

With EPSILON=64 the benchmark with 200MB of keys shows that this PGM index requires only 2% + * additional memory on average (40KB). It depends on the distribution of the keys. This epsilon + * value is good even for 2MB of keys. With EPSILON=32: +5% speed, but 4x space (160KB). + */ + public static final int EPSILON = 64; + + /** + * Epsilon approximation range for the segments layers. Controls the size of the search range in + * the hierarchical segment lists, strictly greater than 0. + */ + public static final int EPSILON_RECURSIVE = 32; + + /** Size of a key, measured in {@link Integer#BYTES} because the key is stored in an int[]. */ + public static final int KEY_SIZE = + RamUsageEstimator.primitiveSizes.get(long.class) / Integer.BYTES; + + /** 2x {@link #KEY_SIZE}. */ + public static final int DOUBLE_KEY_SIZE = KEY_SIZE * 2; + + /** + * Data size of a segment, measured in {@link Integer#BYTES}, because segments are stored in an + * int[]. + */ + public static final int SEGMENT_DATA_SIZE = KEY_SIZE * 3; + + /** Initial value of the exponential jump when scanning out of the epsilon range. */ + public static final int BEYOND_EPSILON_JUMP = 16; + + /** + * The list of keys for which this index is built. It is sorted and may contain duplicate + * elements. + */ + public final LongArrayList keys; + + /** The size of the key set. That is, the number of distinct elements in {@link #keys}. */ + public final int size; + + /** The lowest key in {@link #keys}. */ + public final long firstKey; + + /** The highest key in {@link #keys}. */ + public final long lastKey; + + /** The epsilon range used to build this index. */ + public final int epsilon; + + /** The recursive epsilon range used to build this index. */ + public final int epsilonRecursive; + + /** The offsets in {@link #segmentData} of the first segment of each segment level. */ + public final int[] levelOffsets; + + /** The index data. It contains all the segments for all the levels. */ + public final int[] segmentData; + + private LongPgmIndex( + LongArrayList keys, + int size, + int epsilon, + int epsilonRecursive, + int[] levelOffsets, + int[] segmentData) { + assert keys.size() > 0; + assert size > 0 && size <= keys.size(); + assert epsilon > 0; + assert epsilonRecursive > 0; + this.keys = keys; + this.size = size; + firstKey = keys.get(0); + lastKey = keys.get(keys.size() - 1); + this.epsilon = epsilon; + this.epsilonRecursive = epsilonRecursive; + this.levelOffsets = levelOffsets; + this.segmentData = segmentData; + } + + /** Empty set constructor. */ + private LongPgmIndex() { + keys = new LongArrayList(0); + size = 0; + firstKey = 0L; + lastKey = 0L; + epsilon = 0; + epsilonRecursive = 0; + levelOffsets = new int[0]; + segmentData = levelOffsets; + } + + /** Returns the size of the key set. That is, the number of distinct elements in {@link #keys}. */ + public int size() { + return size; + } + + /** Returns whether this key set is empty. */ + public boolean isEmpty() { + return size() == 0; + } + + /** Returns whether this key set contains the given key. */ + public boolean contains(long key) { + return indexOf(key) >= 0; + } + + /** + * Searches the specified key, and returns its index in the element list. If multiple elements are + * equal to the specified key, there is no guarantee which one will be found. + * + * @return The index of the searched key if it is present; otherwise, {@code (-(insertion + * point) - 1)}. The insertion point is defined as the point at which the key would + * be inserted into the list: the index of the first element greater than the key, or {@link + * #keys}#{@code size()} if all the elements are less than the specified key. Note that this + * guarantees that the return value will be >= 0 if and only if the key is found. + */ + public int indexOf(long key) { + if (key < firstKey) { + return -1; + } + if (key > lastKey) { + return -keys.size() - 1; + } + final int[] segmentData = this.segmentData; + int segmentDataIndex = findSegment(key); + int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData); + int index = + Math.min( + approximateIndex(key, segmentDataIndex, segmentData), + Math.min(nextIntercept, keys.size() - 1)); + assert index >= 0 && index < keys.size(); + long k = keys.get(index); + if (key < k) { + // Scan sequentially before the approximated index, within epsilon range. + final int fromIndex = Math.max(index - epsilon - 1, 0); + while (--index >= fromIndex) { + k = keys.get(index); + if (key > k) { + return -index - 2; + } + if (((key) == (k))) { + return index; + } + } + // Continue scanning out of the epsilon range. + // This might happen in rare cases of precision error during the approximation + // computation for longs (we don't have long double 128 bits in Java). + // This might also happen in rare corner cases of large duplicate elements + // sequence at the epsilon range boundary. + index++; + int jump = BEYOND_EPSILON_JUMP; + do { + int loIndex = Math.max(index - jump, 0); + if (key >= keys.get(loIndex)) { + return Arrays.binarySearch(keys.buffer, loIndex, index, key); + } + index = loIndex; + jump <<= 1; + } while (index > 0); + return -1; + } else if (((key) == (k))) { + return index; + } else { + // Scan sequentially after the approximated index, within epsilon range. + final int toIndex = Math.min(index + epsilon + 3, keys.size()); + while (++index < toIndex) { + k = keys.get(index); + if (key < k) { + return -index - 1; + } + if (((key) == (k))) { + return index; + } + } + // Continue scanning out of the epsilon range. + int jump = BEYOND_EPSILON_JUMP; + do { + int hiIndex = Math.min(index + jump, keys.size()); + if (key <= keys.get(hiIndex)) { + return Arrays.binarySearch(keys.buffer, index, hiIndex, key); + } + index = hiIndex; + jump <<= 1; + } while (index < keys.size()); + return -keys.size() - 1; + } + } + + /** + * Returns, for any value {@code x}, the number of keys in the sorted list which are smaller than + * {@code x}. It is equal to {@link #indexOf} if {@code x} belongs to the list, or -{@link + * #indexOf}-1 otherwise. + * + *

If multiple elements are equal to the specified key, there is no guarantee which one will be + * found. + * + * @return The index of the searched key if it is present; otherwise, the {@code insertion point}. + * The insertion point is defined as the point at which the key would be inserted into + * the list: the index of the first element greater than the key, or {@link #keys}#{@code + * size()} if all the elements are less than the specified key. Note that this method always + * returns a value >= 0. + */ + public int rank(long x) { + int index = indexOf(x); + return index >= 0 ? index : -index - 1; + } + + /** + * Returns the number of keys in the list that are greater than or equal to {@code minKey} + * (inclusive), and less than or equal to {@code maxKey} (inclusive). + */ + public int rangeCardinality(long minKey, long maxKey) { + int fromIndex = rank(minKey); + int maxIndex = indexOf(maxKey); + int toIndex = maxIndex >= 0 ? maxIndex + 1 : -maxIndex - 1; + return Math.max(toIndex - fromIndex, 0); + } + + /** + * Returns an iterator over the keys in the list that are greater than or equal to {@code minKey} + * (inclusive), and less than or equal to {@code maxKey} (inclusive). + */ + public Iterator rangeIterator(long minKey, long maxKey) { + int fromIndex = rank(minKey); + return new RangeIterator(keys, fromIndex, maxKey); + } + + /** + * Applies {@code procedure} to the keys in the list that are greater than or equal to {@code + * minKey} (inclusive), and less than or equal to {@code maxKey} (inclusive). + */ + public T forEachInRange(T procedure, long minKey, long maxKey) { + final long[] buffer = keys.buffer; + long k; + for (int i = rank(minKey), size = keys.size(); i < size && (k = buffer[i]) <= maxKey; i++) { + procedure.apply(k); + } + return procedure; + } + + /** + * Estimates the allocated memory. It does not count the memory for the list of keys, only for the + * index itself. + */ + @Override + public long ramBytesAllocated() { + // int: size, epsilon, epsilonRecursive + // long: firstKey, lastKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 3 * Integer.BYTES + + 2L * KEY_SIZE * Integer.BYTES + // + keys.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(levelOffsets) + + RamUsageEstimator.shallowSizeOfArray(segmentData); + } + + /** + * Estimates the bytes that are actually used. It does not count the memory for the list of keys, + * only for the index itself. + */ + @Override + public long ramBytesUsed() { + // int: size, epsilon, epsilonRecursive + // long: firstKey, lastKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 3 * Integer.BYTES + + 2L * KEY_SIZE * Integer.BYTES + // + keys.ramBytesUsed() + + RamUsageEstimator.shallowSizeOfArray(levelOffsets) + + RamUsageEstimator.shallowSizeOfArray(segmentData); + } + + /** + * Finds the segment responsible for a given key, that is, the rightmost segment having its first + * key <= the searched key. + * + * @return the segment data index; or -1 if none. + */ + private int findSegment(long key) { + assert key >= firstKey && key <= lastKey; + final int epsilonRecursive = this.epsilonRecursive; + final int[] levelOffsets = this.levelOffsets; + final int[] segmentData = this.segmentData; + int level = levelOffsets.length - 1; + int segmentDataIndex = levelOffsets[level] * SEGMENT_DATA_SIZE; + while (--level >= 0) { + int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData); + int index = Math.min(approximateIndex(key, segmentDataIndex, segmentData), nextIntercept); + assert index >= 0 && index <= levelOffsets[level + 1] - levelOffsets[level] - 1; + int sdIndex = (levelOffsets[level] + index) * SEGMENT_DATA_SIZE; + if (getKey(sdIndex, segmentData) <= key) { + // Scan sequentially segments after the approximated index, within the epsilon range. + final int levelNumSegments = levelOffsets[level + 1] - levelOffsets[level] - 1; + final int toIndex = Math.min(index + epsilonRecursive + 3, levelNumSegments); + while (index++ < toIndex && getKey(sdIndex + SEGMENT_DATA_SIZE, segmentData) <= key) { + sdIndex += SEGMENT_DATA_SIZE; + } + } else { + // Scan sequentially segments before the approximated index, within the epsilon range. + final int fromIndex = Math.max(index - epsilonRecursive - 1, 0); + while (index-- > fromIndex) { + sdIndex -= SEGMENT_DATA_SIZE; + if (getKey(sdIndex, segmentData) <= key) { + break; + } + } + } + segmentDataIndex = sdIndex; + } + assert segmentDataIndex >= 0; + return segmentDataIndex; + } + + private int approximateIndex(long key, int segmentDataIndex, int[] segmentData) { + long intercept = getIntercept(segmentDataIndex, segmentData); + long sKey = getKey(segmentDataIndex, segmentData); + double slope = getSlope(segmentDataIndex, segmentData); + int index = (int) (slope * ((double) key - sKey) + intercept); + return Math.max(index, 0); + } + + private static long getIntercept(int segmentDataIndex, int[] segmentData) { + return PgmIndexUtil.getIntercept(segmentDataIndex, segmentData, KEY_SIZE); + } + + private long getKey(int segmentDataIndex, int[] segmentData) { + return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0L); + } + + private static double getSlope(int segmentDataIndex, int[] segmentData) { + return PgmIndexUtil.getSlope(segmentDataIndex + DOUBLE_KEY_SIZE, segmentData, KEY_SIZE); + } + + /** Empty immutable PGM Index. */ + private static class LongEmptyPgmIndex extends LongPgmIndex { + + private final Iterator emptyIterator = new LongEmptyIterator(); + + @Override + public int indexOf(long key) { + return -1; + } + + @Override + public Iterator rangeIterator(long minKey, long maxKey) { + return emptyIterator; + } + + @Override + public T forEachInRange(T procedure, long minKey, long maxKey) { + return procedure; + } + + private static class LongEmptyIterator extends AbstractIterator { + @Override + protected LongCursor fetch() { + return done(); + } + } + } + + /** Iterator over a range of elements in a sorted array. */ + protected static class RangeIterator extends AbstractIterator { + private final long[] buffer; + private final int size; + private final LongCursor cursor; + private final long maxKey; + + /** Range iterator from {@code fromIndex} (inclusive) to {@code maxKey} (inclusive). */ + protected RangeIterator(LongArrayList keys, int fromIndex, long maxKey) { + this.buffer = keys.buffer; + this.size = keys.size(); + this.cursor = new LongCursor(); + this.cursor.index = fromIndex; + this.maxKey = maxKey; + } + + @Override + protected LongCursor fetch() { + if (cursor.index >= size) { + return done(); + } + cursor.value = buffer[cursor.index++]; + if (cursor.value > maxKey) { + cursor.index = size; + return done(); + } + return cursor; + } + } + + /** Builds a {@link LongPgmIndex} on a provided sorted list of keys. */ + public static class LongBuilder implements PlaModel.SegmentConsumer, Accountable { + + protected LongArrayList keys; + protected int epsilon = EPSILON; + protected int epsilonRecursive = EPSILON_RECURSIVE; + protected PlaModel plam; + protected int size; + protected IntArrayList segmentData; + protected int numSegments; + + /** Sets the sorted list of keys to build the index for; duplicate elements are allowed. */ + public LongBuilder setSortedKeys(LongArrayList keys) { + this.keys = keys; + return this; + } + + /** Sets the sorted array of keys to build the index for; duplicate elements are allowed. */ + public LongBuilder setSortedKeys(long[] keys, int length) { + LongArrayList keyList = new LongArrayList(0); + keyList.buffer = keys; + keyList.elementsCount = length; + return setSortedKeys(keyList); + } + + /** Sets the epsilon range to use when learning the segments for the list of keys. */ + public LongBuilder setEpsilon(int epsilon) { + if (epsilon <= 0) { + throw new IllegalArgumentException("epsilon must be > 0"); + } + this.epsilon = epsilon; + return this; + } + + /** + * Sets the recursive epsilon range to use when learning the segments for the segment levels. + */ + public LongBuilder setEpsilonRecursive(int epsilonRecursive) { + if (epsilonRecursive <= 0) { + throw new IllegalArgumentException("epsilonRecursive must be > 0"); + } + this.epsilonRecursive = epsilonRecursive; + return this; + } + + /** Builds the {@link LongPgmIndex}; or {@link #EMPTY} if there are no keys in the list. */ + public LongPgmIndex build() { + if (keys == null || keys.size() == 0) { + return (LongPgmIndex) EMPTY; + } + plam = new PlaModel(epsilon); + + int segmentsInitialCapacity = + Math.min( + Math.max(keys.size() / (2 * epsilon * epsilon) * SEGMENT_DATA_SIZE, 16), 1 << 19); + segmentData = new IntArrayList(segmentsInitialCapacity); + IntArrayList levelOffsets = new IntArrayList(16); + + int levelOffset = 0; + levelOffsets.add(levelOffset); + int levelNumSegments = buildFirstLevel(); + while (levelNumSegments > 1) { + int nextLevelOffset = numSegments; + levelOffsets.add(nextLevelOffset); + levelNumSegments = buildUpperLevel(levelOffset, levelNumSegments); + levelOffset = nextLevelOffset; + } + + int[] segmentDataFinal = segmentData.toArray(); + int[] levelOffsetsFinal = levelOffsets.toArray(); + return new LongPgmIndex( + keys, size, epsilon, epsilonRecursive, levelOffsetsFinal, segmentDataFinal); + } + + private int buildFirstLevel() { + assert numSegments == 0; + int numKeys = keys.size(); + int size = 0; + long key = keys.get(0); + size++; + plam.addKey(key, 0, this); + for (int i = 1; i < numKeys; i++) { + long nextKey = keys.get(i); + if (!((nextKey) == (key))) { + key = nextKey; + plam.addKey(key, i, this); + size++; + } + } + plam.finish(this); + addSentinelSegment(numKeys); + this.size = size; + return numSegments - 1; + } + + private int buildUpperLevel(int levelOffset, int levelNumSegments) { + plam.setEpsilon(epsilonRecursive); + assert numSegments > 0; + int initialNumSegments = numSegments; + int segmentDataIndex = levelOffset * SEGMENT_DATA_SIZE; + long key = getKey(segmentDataIndex, segmentData.buffer); + plam.addKey(key, 0, this); + for (int i = 1; i < levelNumSegments; i++) { + segmentDataIndex += SEGMENT_DATA_SIZE; + long nextKey = getKey(segmentDataIndex, segmentData.buffer); + if (!((nextKey) == (key))) { + key = nextKey; + plam.addKey(key, i, this); + } + } + plam.finish(this); + addSentinelSegment(levelNumSegments); + return numSegments - initialNumSegments - 1; + } + + private long getKey(int segmentDataIndex, int[] segmentData) { + return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0L); + } + + /** + * Adds a sentinel segment that is used to give a limit for the position approximation, but does + * not count in the number of segments per level. + */ + private void addSentinelSegment(int endIndex) { + // This sentinel segment is used in findSegment(). + accept(Double.MAX_VALUE, 0d, endIndex); + } + + @Override + public void accept(double firstKey, double slope, long intercept) { + PgmIndexUtil.addIntercept(intercept, segmentData, KEY_SIZE); + PgmIndexUtil.addKey((long) firstKey, segmentData); + PgmIndexUtil.addSlope(slope, segmentData, KEY_SIZE); + numSegments++; + assert segmentData.size() == numSegments * SEGMENT_DATA_SIZE; + } + + /** + * Estimates the allocated memory. It does not count the memory for the list of keys, only for + * the builder itself. + */ + @Override + public long ramBytesAllocated() { + // int: epsilon, epsilonRecursive, size, numSegments + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + // + keys.ramBytesAllocated() + + plam.ramBytesAllocated() + + segmentData.ramBytesAllocated(); + } + + /** + * Estimates the bytes that are actually used. It does not count the memory for the list of + * keys, only for the builder itself. + */ + @Override + public long ramBytesUsed() { + // int: epsilon, epsilonRecursive, size, numSegments + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + // + keys.ramBytesUsed() + + plam.ramBytesUsed() + + segmentData.ramBytesUsed(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/LongSet.java b/src/main/java/com/carrotsearch/hppc/LongSet.java new file mode 100755 index 00000000..69a3144a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongSet.java @@ -0,0 +1,33 @@ +package com.carrotsearch.hppc; + +/** A set of longs. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeSet.java") +public interface LongSet extends LongCollection { + /** + * Adds k to the set. + * + * @return Returns true if this element was not part of the set before. Returns + * false if an equal element is already part of the set, does not replace the + * existing element with the argument. + */ + public boolean add(long k); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); + + /** + * Adds all elements from the given {@link LongContainer} to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + * @since 0.9.1 + */ + public int addAll(LongContainer container); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongShortAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/LongShortAssociativeContainer.java new file mode 100755 index 00000000..e9f9f677 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongShortAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see LongContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface LongShortAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(long key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(LongShortPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link LongShortProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link LongShortPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public LongCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public ShortContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongShortHashMap.java b/src/main/java/com/carrotsearch/hppc/LongShortHashMap.java new file mode 100755 index 00000000..cf9a34c8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongShortHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of long to short, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeHashMap.java") +public class LongShortHashMap implements LongShortMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public long[] keys; + + /** The array holding values. */ + public short[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public LongShortHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public LongShortHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public LongShortHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public LongShortHashMap(LongShortAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public short put(long key, short value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + short previousValue = hasEmptyKey ? values[mask + 1] : ((short) 0); + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final short previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return ((short) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(LongShortAssociativeContainer container) { + final int count = size(); + for (LongShortCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (LongShortCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public short putOrAdd(long key, short putValue, short incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((short) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public short addTo(long key, short incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public short remove(long key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return ((short) 0); + } + hasEmptyKey = false; + short previousValue = values[mask + 1]; + values[mask + 1] = ((short) 0); + return previousValue; + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final short previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return ((short) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof LongLookupContainer) { + if (hasEmptyKey && other.contains(0L)) { + hasEmptyKey = false; + values[mask + 1] = ((short) 0); + } + + final long[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + long existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (LongCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongShortPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(0L, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = ((short) 0); + } + } + + final long[] keys = this.keys; + final short[] values = this.values; + for (int slot = 0; slot <= mask; ) { + long existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(LongPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(0L)) { + hasEmptyKey = false; + values[mask + 1] = ((short) 0); + } + } + + final long[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + long existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public short get(long key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : ((short) 0); + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return ((short) 0); + } + } + + /** {@inheritDoc} */ + @Override + public short getOrDefault(long key, short defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(long key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final long[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(long key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final long[] keys = this.keys; + int slot = hashKey(key) & mask; + + long existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public short indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public short indexReplace(int index, short newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + short previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, long key, short value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public short indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + short previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = ((short) 0); + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, 0L); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (LongShortCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(LongShortHashMap other) { + if (other.size() != size()) { + return false; + } + + for (LongShortCursor c : other) { + long key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final long[] prevKeys = this.keys; + final short[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final LongShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new LongShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongShortCursor fetch() { + final int mask = LongShortHashMap.this.mask; + while (index <= mask) { + long existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = 0L; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final long[] keys = this.keys; + final short[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(0L, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final long[] keys = this.keys; + final short[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(0L, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { + private final LongShortHashMap owner = LongShortHashMap.this; + + @Override + public boolean contains(long e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((LongShortProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((LongShortPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(LongPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final long e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final LongCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new LongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongCursor fetch() { + final int mask = LongShortHashMap.this.mask; + while (index <= mask) { + long existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = 0L; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public ShortCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractShortCollection { + private final LongShortHashMap owner = LongShortHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(short value) { + for (LongShortCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (LongShortCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (LongShortCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final short e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final ShortPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new ShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortCursor fetch() { + final int mask = LongShortHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public LongShortHashMap clone() { + try { + + LongShortHashMap cloned = (LongShortHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (LongShortCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return LongBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static LongShortHashMap from(long[] keys, short[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + LongShortHashMap map = new LongShortHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(long key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(long[] fromKeys, short[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final long[] keys = this.keys; + final short[] values = this.values; + final int mask = this.mask; + long existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + long[] prevKeys = this.keys; + short[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new long[arraySize + emptyElementSlot]); + this.values = (new short[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, long pendingKey, short pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final long[] prevKeys = this.keys; + final short[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final long[] keys = this.keys; + final short[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final long existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = 0L; + values[gapSlot] = ((short) 0); + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/LongShortMap.java b/src/main/java/com/carrotsearch/hppc/LongShortMap.java new file mode 100755 index 00000000..3ef50522 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongShortMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.LongShortCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface LongShortMap extends LongShortAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public short get(long key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public short getOrDefault(long key, short defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public short put(long key, short value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(long key, short value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(LongShortAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public short putOrAdd(long key, short putValue, short incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public short addTo(long key, short additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public short remove(long key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link LongShortMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(long key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public short indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public short indexReplace(int index, short newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, long key, short value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public short indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/LongStack.java b/src/main/java/com/carrotsearch/hppc/LongStack.java new file mode 100755 index 00000000..6d5f15ff --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongStack.java @@ -0,0 +1,137 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.LongCursor; + +/** + * A subclass of {@link LongArrayList} adding stack-related utility methods. The top of the stack is + * at the {@link #size()} - 1 element. + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java") +public class LongStack extends LongArrayList { + /** New instance with sane defaults. */ + public LongStack() { + super(); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public LongStack(int expectedElements) { + super(expectedElements); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public LongStack(int expectedElements, ArraySizingStrategy resizer) { + super(expectedElements, resizer); + } + + /** Create a stack by pushing all elements of another container to it. */ + public LongStack(LongContainer container) { + super(container); + } + + /** Adds one long to the stack. */ + public void push(long e1) { + ensureBufferSpace(1); + buffer[elementsCount++] = e1; + } + + /** Adds two longs to the stack. */ + public void push(long e1, long e2) { + ensureBufferSpace(2); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + } + + /** Adds three longs to the stack. */ + public void push(long e1, long e2, long e3) { + ensureBufferSpace(3); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + buffer[elementsCount++] = e3; + } + + /** Adds four longs to the stack. */ + public void push(long e1, long e2, long e3, long e4) { + ensureBufferSpace(4); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + buffer[elementsCount++] = e3; + buffer[elementsCount++] = e4; + } + + /** Add a range of array elements to the stack. */ + public void push(long[] elements, int start, int len) { + assert start >= 0 && len >= 0; + + ensureBufferSpace(len); + System.arraycopy(elements, start, buffer, elementsCount, len); + elementsCount += len; + } + + /** + * Vararg-signature method for pushing elements at the top of the stack. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + */ + public final void push(long... elements) { + push(elements, 0, elements.length); + } + + /** Pushes all elements from another container to the top of the stack. */ + public int pushAll(LongContainer container) { + return addAll(container); + } + + /** Pushes all elements from another iterable to the top of the stack. */ + public int pushAll(Iterable iterable) { + return addAll(iterable); + } + + /** Discard an arbitrary number of elements from the top of the stack. */ + public void discard(int count) { + assert elementsCount >= count; + + elementsCount -= count; + } + + /** Discard the top element from the stack. */ + public void discard() { + assert elementsCount > 0; + + elementsCount--; + } + + /** Remove the top element from the stack and return it. */ + public long pop() { + return removeLast(); + } + + /** Peek at the top element on the stack. */ + public long peek() { + assert elementsCount > 0; + return buffer[elementsCount - 1]; + } + + /** Create a stack by pushing a variable number of arguments to it. */ + public static LongStack from(long... elements) { + final LongStack stack = new LongStack(elements.length); + stack.push(elements); + return stack; + } + + /** {@inheritDoc} */ + @Override + public LongStack clone() { + return (LongStack) super.clone(); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectArrayDeque.java b/src/main/java/com/carrotsearch/hppc/ObjectArrayDeque.java new file mode 100755 index 00000000..a25261f8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectArrayDeque.java @@ -0,0 +1,786 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; + +import com.carrotsearch.hppc.cursors.ObjectCursor; +import com.carrotsearch.hppc.predicates.ObjectPredicate; +import com.carrotsearch.hppc.procedures.ObjectProcedure; +import java.util.*; + +/** An array-backed {@link ObjectDeque}. */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java") +public class ObjectArrayDeque extends AbstractObjectCollection + implements ObjectDeque, Preallocable, Cloneable, Accountable { + + /** Reuse the same strategy instance. */ + private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = + BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; + + /** Internal array for storing elements of the deque. */ + public Object[] buffer = ObjectArrayList.EMPTY_ARRAY; + + /** + * The index of the element at the head of the deque or an arbitrary number equal to tail if the + * deque is empty. + */ + public int head; + + /** The index at which the next element would be added to the tail of the deque. */ + public int tail; + + /** Buffer resizing strategy. */ + protected final ArraySizingStrategy resizer; + + /** New instance with sane defaults. */ + public ObjectArrayDeque() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectArrayDeque(int expectedElements) { + this(expectedElements, DEFAULT_SIZING_STRATEGY); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public ObjectArrayDeque(int expectedElements, ArraySizingStrategy resizer) { + assert resizer != null; + this.resizer = resizer; + ensureCapacity(expectedElements); + } + + /** + * Creates a new deque from elements of another container, appending elements at the end of the + * deque in the iteration order. + */ + public ObjectArrayDeque(ObjectContainer container) { + this(container.size()); + addLast(container); + } + + /** {@inheritDoc} */ + @Override + public void addFirst(KType e1) { + int h = oneLeft(head, buffer.length); + if (h == tail) { + ensureBufferSpace(1); + h = oneLeft(head, buffer.length); + } + buffer[head = h] = e1; + } + + /** + * Vararg-signature method for adding elements at the front of this deque. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + * + * @param elements The elements to add. + */ + @SafeVarargs + public final void addFirst(KType... elements) { + ensureBufferSpace(elements.length); + for (KType k : elements) { + addFirst(k); + } + } + + /** + * Inserts all elements from the given container to the front of this deque. + * + * @param container The container to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addFirst(ObjectContainer container) { + int size = container.size(); + ensureBufferSpace(size); + + for (ObjectCursor cursor : container) { + addFirst(cursor.value); + } + + return size; + } + + /** + * Inserts all elements from the given iterable to the front of this deque. + * + * @param iterable The iterable to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addFirst(Iterable> iterable) { + int size = 0; + for (ObjectCursor cursor : iterable) { + addFirst(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public void addLast(KType e1) { + int t = oneRight(tail, buffer.length); + if (head == t) { + ensureBufferSpace(1); + t = oneRight(tail, buffer.length); + } + buffer[tail] = e1; + tail = t; + } + + /** + * Vararg-signature method for adding elements at the end of this deque. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + * + * @param elements The elements to iterate over. + */ + @SafeVarargs + public final void addLast(KType... elements) { + ensureBufferSpace(1); + for (KType k : elements) { + addLast(k); + } + } + + /** + * Inserts all elements from the given container to the end of this deque. + * + * @param container The container to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addLast(ObjectContainer container) { + int size = container.size(); + ensureBufferSpace(size); + + for (ObjectCursor cursor : container) { + addLast(cursor.value); + } + + return size; + } + + /** + * Inserts all elements from the given iterable to the end of this deque. + * + * @param iterable The iterable to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addLast(Iterable> iterable) { + int size = 0; + for (ObjectCursor cursor : iterable) { + addLast(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public KType removeFirst() { + assert size() > 0 : "The deque is empty."; + + final KType result = (KType) buffer[head]; + buffer[head] = null; + head = oneRight(head, buffer.length); + return result; + } + + /** {@inheritDoc} */ + @Override + public KType removeLast() { + assert size() > 0 : "The deque is empty."; + + tail = oneLeft(tail, buffer.length); + final KType result = (KType) buffer[tail]; + buffer[tail] = null; + return result; + } + + /** {@inheritDoc} */ + @Override + public KType getFirst() { + assert size() > 0 : "The deque is empty."; + + return (KType) buffer[head]; + } + + /** {@inheritDoc} */ + @Override + public KType getLast() { + assert size() > 0 : "The deque is empty."; + + return (KType) buffer[oneLeft(tail, buffer.length)]; + } + + /** {@inheritDoc} */ + @Override + public int removeFirst(KType e1) { + final int index = bufferIndexOf(e1); + if (index >= 0) removeAtBufferIndex(index); + return index; + } + + /** + * Return the index of the first (counting from head) element equal to e1. The index + * points to the {@link #buffer} array. + * + * @param e1 The element to look for. + * @return Returns the index of the first element equal to e1 or -1 if + * not found. + */ + public int bufferIndexOf(KType e1) { + final int last = tail; + final int bufLen = buffer.length; + for (int i = head; i != last; i = oneRight(i, bufLen)) { + if (this.equals(e1, buffer[i])) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int removeLast(KType e1) { + final int index = lastBufferIndexOf(e1); + if (index >= 0) { + removeAtBufferIndex(index); + } + return index; + } + + /** + * Return the index of the last (counting from tail) element equal to e1. The index + * points to the {@link #buffer} array. + * + * @param e1 The element to look for. + * @return Returns the index of the first element equal to e1 or -1 if + * not found. + */ + public int lastBufferIndexOf(KType e1) { + final int bufLen = buffer.length; + final int last = oneLeft(head, bufLen); + for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) { + if (this.equals(e1, buffer[i])) return i; + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(KType e1) { + int removed = 0; + final int last = tail; + final int bufLen = buffer.length; + int from, to; + for (from = to = head; from != last; from = oneRight(from, bufLen)) { + if (this.equals(e1, buffer[from])) { + buffer[from] = null; + removed++; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = null; + } + + to = oneRight(to, bufLen); + } + + tail = to; + return removed; + } + + /** + * Removes the element at index in the internal {#link {@link #buffer} array, + * returning its value. + * + * @param index Index of the element to remove. The index must be located between {@link #head} + * and {@link #tail} in modulo {@link #buffer} arithmetic. + */ + public void removeAtBufferIndex(int index) { + assert (head <= tail ? index >= head && index < tail : index >= head || index < tail) + : "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ")."; + + // Cache fields in locals (hopefully moved to registers). + final KType[] buffer = (KType[]) this.buffer; + final int bufLen = buffer.length; + final int lastIndex = bufLen - 1; + final int head = this.head; + final int tail = this.tail; + + final int leftChunk = Math.abs(index - head) % bufLen; + final int rightChunk = Math.abs(tail - index) % bufLen; + + if (leftChunk < rightChunk) { + if (index >= head) { + System.arraycopy(buffer, head, buffer, head + 1, leftChunk); + } else { + System.arraycopy(buffer, 0, buffer, 1, index); + buffer[0] = buffer[lastIndex]; + System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head); + } + buffer[head] = null; + this.head = oneRight(head, bufLen); + } else { + if (index < tail) { + System.arraycopy(buffer, index + 1, buffer, index, rightChunk); + } else { + System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index); + buffer[lastIndex] = buffer[0]; + System.arraycopy(buffer, 1, buffer, 0, tail); + } + buffer[tail] = null; + this.tail = oneLeft(tail, bufLen); + } + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int size() { + if (head <= tail) return tail - head; + else return (tail - head + buffer.length); + } + + /** + * {@inheritDoc} + * + *

The internal array buffers are not released as a result of this call. + * + * @see #release() + */ + @Override + public void clear() { + if (head < tail) { + Arrays.fill(buffer, head, tail, null); + } else { + Arrays.fill(buffer, 0, tail, null); + Arrays.fill(buffer, head, buffer.length, null); + } + this.head = tail = 0; + } + + /** Release internal buffers of this deque and reallocate with the default buffer. */ + public void release() { + this.head = tail = 0; + buffer = ObjectArrayList.EMPTY_ARRAY; + ensureBufferSpace(0); + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + ensureBufferSpace(expectedElements - size()); + } + + /** + * Ensures the internal buffer has enough free slots to store expectedAdditions. + * Increases internal buffer size if needed. + */ + protected void ensureBufferSpace(int expectedAdditions) { + final int bufferLen = buffer.length; + final int elementsCount = size(); + + if (elementsCount + expectedAdditions >= bufferLen) { + final int emptySlot = 1; // deque invariant: always an empty slot. + final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions); + assert newSize >= (elementsCount + expectedAdditions + emptySlot) + : "Resizer failed to" + + " return sensible new size: " + + newSize + + " <= " + + (elementsCount + expectedAdditions); + + try { + final KType[] newBuffer = ((KType[]) new Object[newSize]); + if (bufferLen > 0) { + toArray(newBuffer); + tail = elementsCount; + head = 0; + } + this.buffer = newBuffer; + } catch (OutOfMemoryError e) { + throw new BufferAllocationException( + "Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize); + } + } + } + + /** {@inheritDoc} */ + @Override + public Object[] toArray() { + + final int size = size(); + return toArray(((KType[]) new Object[size])); + } + + /** + * Copies elements of this deque to an array. The content of the target array is + * filled from index 0 (head of the queue) to index size() - 1 (tail of the queue). + * + * @param target The target array must be large enough to hold all elements. + * @return Returns the target argument for chaining. + */ + public KType[] toArray(KType[] target) { + assert target.length >= size() : "Target array must be >= " + size(); + + if (head < tail) { + // The contents is not wrapped around. Just copy. + System.arraycopy(buffer, head, target, 0, size()); + } else if (head > tail) { + // The contents is split. Merge elements from the following indexes: + // [head...buffer.length - 1][0, tail - 1] + final int rightCount = buffer.length - head; + System.arraycopy(buffer, head, target, 0, rightCount); + System.arraycopy(buffer, 0, target, rightCount, tail); + } + + return target; + } + + /** + * Clone this object. The returned clone will reuse the same hash function and array resizing + * strategy. + */ + @Override + public ObjectArrayDeque clone() { + try { + + ObjectArrayDeque cloned = (ObjectArrayDeque) super.clone(); + cloned.buffer = buffer.clone(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Move one index to the left, wrapping around buffer. */ + protected static int oneLeft(int index, int modulus) { + if (index >= 1) { + return index - 1; + } + return modulus - 1; + } + + /** Move one index to the right, wrapping around buffer. */ + protected static int oneRight(int index, int modulus) { + if (index + 1 == modulus) { + return 0; + } + return index + 1; + } + + @Override + public long ramBytesAllocated() { + // int: head, tail + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES * 2 + + resizer.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(buffer); + } + + @Override + public long ramBytesUsed() { + // int: head, tail + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES * 2 + + resizer.ramBytesUsed() + + RamUsageEstimator.shallowUsedSizeOfArray(buffer, size()); + } + + /** An iterator implementation for {@link ObjectArrayDeque#iterator}. */ + private final class ValueIterator extends AbstractIterator> { + private final ObjectCursor cursor; + private int remaining; + + public ValueIterator() { + cursor = new ObjectCursor(); + cursor.index = oneLeft(head, buffer.length); + this.remaining = size(); + } + + @Override + protected ObjectCursor fetch() { + if (remaining == 0) { + return done(); + } + + remaining--; + cursor.value = (KType) buffer[cursor.index = oneRight(cursor.index, buffer.length)]; + return cursor; + } + } + + /** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */ + private final class DescendingValueIterator extends AbstractIterator> { + private final ObjectCursor cursor; + private int remaining; + + public DescendingValueIterator() { + cursor = new ObjectCursor(); + cursor.index = tail; + this.remaining = size(); + } + + @Override + protected ObjectCursor fetch() { + if (remaining == 0) return done(); + + remaining--; + cursor.value = (KType) buffer[cursor.index = oneLeft(cursor.index, buffer.length)]; + return cursor; + } + } + + /** + * Returns a cursor over the values of this deque (in head to tail order). The iterator is + * implemented as a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in + * the deque's buffer) use the cursor's public fields. An example is shown below. + * + *

+   * for (IntValueCursor c : intDeque) {
+   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator> iterator() { + return new ValueIterator(); + } + + /** + * Returns a cursor over the values of this deque (in tail to head order). The iterator is + * implemented as a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in + * the deque's buffer) use the cursor's public fields. An example is shown below. + * + *
+   * for (Iterator<IntCursor> i = intDeque.descendingIterator(); i.hasNext();) {
+   *   final IntCursor c = i.next();
+   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator> descendingIterator() { + return new DescendingValueIterator(); + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T procedure) { + forEach(procedure, head, tail); + return procedure; + } + + /** + * Applies procedure to a slice of the deque, fromIndex, inclusive, to + * toIndex, exclusive. + */ + private void forEach(ObjectProcedure procedure, int fromIndex, final int toIndex) { + final KType[] buffer = (KType[]) this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + procedure.apply(buffer[i]); + } + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T predicate) { + int fromIndex = head; + int toIndex = tail; + + final KType[] buffer = (KType[]) this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + if (!predicate.apply(buffer[i])) { + break; + } + } + + return predicate; + } + + /** Applies procedure to all elements of this deque, tail to head. */ + @Override + public > T descendingForEach(T procedure) { + descendingForEach(procedure, head, tail); + return procedure; + } + + /** + * Applies procedure to a slice of the deque, toIndex, exclusive, down + * to fromIndex, inclusive. + */ + private void descendingForEach( + ObjectProcedure procedure, int fromIndex, final int toIndex) { + if (fromIndex == toIndex) return; + + final KType[] buffer = (KType[]) this.buffer; + int i = toIndex; + do { + i = oneLeft(i, buffer.length); + procedure.apply(buffer[i]); + } while (i != fromIndex); + } + + /** {@inheritDoc} */ + @Override + public > T descendingForEach(T predicate) { + descendingForEach(predicate, head, tail); + return predicate; + } + + /** + * Applies predicate to a slice of the deque, toIndex, exclusive, down + * to fromIndex, inclusive or until the predicate returns false. + */ + private void descendingForEach( + ObjectPredicate predicate, int fromIndex, final int toIndex) { + if (fromIndex == toIndex) return; + + final KType[] buffer = (KType[]) this.buffer; + int i = toIndex; + do { + i = oneLeft(i, buffer.length); + if (!predicate.apply(buffer[i])) { + break; + } + } while (i != fromIndex); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectPredicate predicate) { + final KType[] buffer = (KType[]) this.buffer; + final int last = tail; + final int bufLen = buffer.length; + int removed = 0; + int from, to; + from = to = head; + try { + for (from = to = head; from != last; from = oneRight(from, bufLen)) { + if (predicate.apply(buffer[from])) { + buffer[from] = null; + removed++; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = null; + } + + to = oneRight(to, bufLen); + } + } finally { + // Keep the deque in consistent state even if the predicate throws an exception. + for (; from != last; from = oneRight(from, bufLen)) { + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = null; + } + + to = oneRight(to, bufLen); + } + tail = to; + } + + return removed; + } + + /** {@inheritDoc} */ + @Override + public boolean contains(KType e) { + int fromIndex = head; + int toIndex = tail; + + final KType[] buffer = (KType[]) this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + if (this.equals(e, buffer[i])) { + return true; + } + } + + return false; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 1; + int fromIndex = head; + int toIndex = tail; + + final KType[] buffer = (KType[]) this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + h = 31 * h + BitMixer.mix(this.buffer[i]); + } + return h; + } + + /** + * Returns true only if the other object is an instance of the same class and with + * the same elements. Equality comparison is performed with this object's {@link #equals(Object, + * Object)} method. + */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** + * Compare order-aligned elements against another {@link ObjectDeque}. Equality comparison is + * performed with this object's {@link #equals(Object, Object)} method. + */ + protected boolean equalElements(ObjectArrayDeque other) { + int max = size(); + if (other.size() != max) { + return false; + } + + Iterator> i1 = this.iterator(); + Iterator> i2 = other.iterator(); + + while (i1.hasNext() && i2.hasNext()) { + if (!this.equals(i1.next().value, i2.next().value)) { + return false; + } + } + + return !i1.hasNext() && !i2.hasNext(); + } + + /** Create a new deque by pushing a variable number of arguments to the end of it. */ + @SafeVarargs + public static ObjectArrayDeque from(KType... elements) { + final ObjectArrayDeque coll = new ObjectArrayDeque(elements.length); + coll.addLast(elements); + return coll; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectArrayList.java b/src/main/java/com/carrotsearch/hppc/ObjectArrayList.java new file mode 100755 index 00000000..e11da848 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectArrayList.java @@ -0,0 +1,604 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.ObjectPredicate; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; +import java.util.stream.Stream; + +/** An array-backed list of Objects. */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java") +public class ObjectArrayList extends AbstractObjectCollection + implements ObjectIndexedContainer, Preallocable, Cloneable, Accountable { + /** An immutable empty buffer (array). */ + public static final Object[] EMPTY_ARRAY = new Object[0]; + + ; + + /** Reuse the same strategy instance. */ + private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = + BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; + + /** + * Internal array for storing the list. The array may be larger than the current size ({@link + * #size()}). + */ + public Object[] buffer = EMPTY_ARRAY; + + /** Current number of elements stored in {@link #buffer}. */ + public int elementsCount; + + /** Buffer resizing strategy. */ + protected final ArraySizingStrategy resizer; + + /** New instance with sane defaults. */ + public ObjectArrayList() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectArrayList(int expectedElements) { + this(expectedElements, DEFAULT_SIZING_STRATEGY); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public ObjectArrayList(int expectedElements, ArraySizingStrategy resizer) { + assert resizer != null; + this.resizer = resizer; + buffer = Arrays.copyOf(buffer, expectedElements); + } + + /** Creates a new list from the elements of another container in its iteration order. */ + public ObjectArrayList(ObjectContainer container) { + this(container.size()); + addAll(container); + } + + /** {@inheritDoc} */ + @Override + public void add(KType e1) { + ensureBufferSpace(1); + buffer[elementsCount++] = e1; + } + + /** + * Appends two elements at the end of the list. To add more than two elements, use add + * (vararg-version) or access the buffer directly (tight loop). + */ + public void add(KType e1, KType e2) { + ensureBufferSpace(2); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + } + + /** Add all elements from a range of given array to the list. */ + public void add(KType[] elements, int start, int length) { + assert length >= 0 : "Length must be >= 0"; + + ensureBufferSpace(length); + System.arraycopy(elements, start, buffer, elementsCount, length); + elementsCount += length; + } + + /** + * Vararg-signature method for adding elements at the end of the list. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + */ + @SafeVarargs + public final void add(KType... elements) { + add(elements, 0, elements.length); + } + + /** Adds all elements from another container. */ + public int addAll(ObjectContainer container) { + final int size = container.size(); + ensureBufferSpace(size); + + for (ObjectCursor cursor : container) { + add(cursor.value); + } + + return size; + } + + /** Adds all elements from another iterable. */ + public int addAll(Iterable> iterable) { + int size = 0; + for (ObjectCursor cursor : iterable) { + add(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public void insert(int index, KType e1) { + assert (index >= 0 && index <= size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + "]."; + + ensureBufferSpace(1); + System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index); + buffer[index] = e1; + elementsCount++; + } + + /** {@inheritDoc} */ + @Override + public KType get(int index) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + return (KType) buffer[index]; + } + + /** {@inheritDoc} */ + @Override + public KType set(int index, KType e1) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + final KType v = (KType) buffer[index]; + buffer[index] = e1; + return v; + } + + /** {@inheritDoc} */ + @Override + public KType removeAt(int index) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + final KType v = (KType) buffer[index]; + System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index); + + buffer[elementsCount] = null; + + return v; + } + + /** {@inheritDoc} */ + @Override + public KType removeLast() { + assert elementsCount > 0; + + final KType v = (KType) buffer[--elementsCount]; + + buffer[elementsCount] = null; + + return v; + } + + /** {@inheritDoc} */ + @Override + public void removeRange(int fromIndex, int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex); + final int count = toIndex - fromIndex; + elementsCount -= count; + + Arrays.fill(buffer, elementsCount, elementsCount + count, null); + } + + /** {@inheritDoc} */ + @Override + public boolean removeElement(KType e1) { + return removeFirst(e1) != -1; + } + + /** {@inheritDoc} */ + @Override + public int removeFirst(KType e1) { + final int index = indexOf(e1); + if (index >= 0) removeAt(index); + return index; + } + + /** {@inheritDoc} */ + @Override + public int removeLast(KType e1) { + final int index = lastIndexOf(e1); + if (index >= 0) removeAt(index); + return index; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(KType e1) { + int to = 0; + for (int from = 0; from < elementsCount; from++) { + if (this.equals(e1, buffer[from])) { + continue; + } + if (to != from) { + buffer[to] = buffer[from]; + } + to++; + } + final int deleted = elementsCount - to; + this.elementsCount = to; + + Arrays.fill(buffer, elementsCount, elementsCount + deleted, null); + + return deleted; + } + + /** {@inheritDoc} */ + @Override + public boolean contains(KType e1) { + return indexOf(e1) >= 0; + } + + /** {@inheritDoc} */ + @Override + public int indexOf(KType e1) { + for (int i = 0; i < elementsCount; i++) { + if (this.equals(e1, buffer[i])) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int lastIndexOf(KType e1) { + for (int i = elementsCount - 1; i >= 0; i--) { + if (this.equals(e1, buffer[i])) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return elementsCount == 0; + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + final int bufferLen = (buffer == null ? 0 : buffer.length); + if (expectedElements > bufferLen) { + ensureBufferSpace(expectedElements - size()); + } + } + + /** + * Ensures the internal buffer has enough free slots to store expectedAdditions. + * Increases internal buffer size if needed. + */ + protected void ensureBufferSpace(int expectedAdditions) { + final int bufferLen = (buffer == null ? 0 : buffer.length); + if (elementsCount + expectedAdditions > bufferLen) { + final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions); + assert newSize >= elementsCount + expectedAdditions + : "Resizer failed to" + + " return sensible new size: " + + newSize + + " <= " + + (elementsCount + expectedAdditions); + + this.buffer = Arrays.copyOf(buffer, newSize); + } + } + + /** + * Truncate or expand the list to the new size. If the list is truncated, the buffer will not be + * reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated + * values will be reset to the default value (zero). If the list is expanded, the elements beyond + * the current size are initialized with JVM-defaults (zero or null values). + */ + public void resize(int newSize) { + if (newSize <= buffer.length) { + if (newSize < elementsCount) { + Arrays.fill(buffer, newSize, elementsCount, null); + } else { + Arrays.fill(buffer, elementsCount, newSize, null); + } + } else { + ensureCapacity(newSize); + } + this.elementsCount = newSize; + } + + /** {@inheritDoc} */ + @Override + public int size() { + return elementsCount; + } + + /** Trim the internal buffer to the current size. */ + public void trimToSize() { + if (size() != this.buffer.length) { + this.buffer = (KType[]) toArray(); + } + } + + /** + * Sets the number of stored elements to zero. Releases and initializes the internal storage array + * to default values. To clear the list without cleaning the buffer, simply set the {@link + * #elementsCount} field to zero. + */ + @Override + public void clear() { + Arrays.fill(buffer, 0, elementsCount, null); + this.elementsCount = 0; + } + + /** Sets the number of stored elements to zero and releases the internal storage array. */ + @Override + public void release() { + this.buffer = (KType[]) EMPTY_ARRAY; + this.elementsCount = 0; + } + + /** + * {@inheritDoc} + * + *

The returned array is sized to match exactly the number of elements of the stack. + */ + @Override + public Object[] toArray() { + + return Arrays.copyOf(buffer, elementsCount); + } + + /** {@inheritDoc} */ + @Override + @SuppressWarnings("unchecked") + public Stream stream() { + return (Stream) Arrays.stream(buffer, 0, size()); + } + + /** {@inheritDoc} */ + @Override + public ObjectIndexedContainer sort() { + Arrays.sort(buffer, 0, elementsCount); + return this; + } + + /** {@inheritDoc} */ + @Override + public ObjectIndexedContainer reverse() { + for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) { + KType tmp = (KType) buffer[i]; + buffer[i] = buffer[j]; + buffer[j] = tmp; + } + return this; + } + + /** + * Clone this object. The returned clone will reuse the same hash function and array resizing + * strategy. + */ + @Override + public ObjectArrayList clone() { + try { + + final ObjectArrayList cloned = (ObjectArrayList) super.clone(); + cloned.buffer = buffer.clone(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 1, max = elementsCount; + for (int i = 0; i < max; i++) { + h = 31 * h + BitMixer.mix(this.buffer[i]); + } + return h; + } + + /** + * Returns true only if the other object is an instance of the same class and with + * the same elements. Equality comparison is performed with this object's {@link #equals(Object, + * Object)} method. + */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** + * Compare index-aligned elements against another {@link ObjectIndexedContainer}. Equality + * comparison is performed with this object's {@link #equals(Object, Object)} method. + */ + protected boolean equalElements(ObjectArrayList other) { + int max = size(); + if (other.size() != max) { + return false; + } + + for (int i = 0; i < max; i++) { + if (!this.equals(get(i), other.get(i))) { + return false; + } + } + + return true; + } + + @Override + public long ramBytesAllocated() { + // int: elementsCount + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES + + resizer.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(buffer); + } + + @Override + public long ramBytesUsed() { + // int: elementsCount + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES + + resizer.ramBytesUsed() + + RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount); + } + + /** An iterator implementation for {@link ObjectArrayList#iterator}. */ + static final class ValueIterator extends AbstractIterator> { + private final ObjectCursor cursor; + + private final KType[] buffer; + private final int size; + + public ValueIterator(KType[] buffer, int size) { + this.cursor = new ObjectCursor(); + this.cursor.index = -1; + this.size = size; + this.buffer = buffer; + } + + @Override + protected ObjectCursor fetch() { + if (cursor.index + 1 == size) return done(); + + cursor.value = buffer[++cursor.index]; + return cursor; + } + } + + /** {@inheritDoc} */ + @Override + public Iterator> iterator() { + return new ValueIterator((KType[]) buffer, size()); + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T procedure) { + return forEach(procedure, 0, size()); + } + + /** + * Applies procedure to a slice of the list, fromIndex, inclusive, to + * toIndex, exclusive. + */ + public > T forEach( + T procedure, int fromIndex, final int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + final KType[] buffer = (KType[]) this.buffer; + for (int i = fromIndex; i < toIndex; i++) { + procedure.apply(buffer[i]); + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectPredicate predicate) { + final KType[] buffer = (KType[]) this.buffer; + final int elementsCount = this.elementsCount; + int to = 0; + int from = 0; + try { + for (; from < elementsCount; from++) { + if (predicate.apply(buffer[from])) { + buffer[from] = null; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = null; + } + to++; + } + } finally { + // Keep the list in a consistent state, even if the predicate throws an exception. + for (; from < elementsCount; from++) { + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = null; + } + to++; + } + + this.elementsCount = to; + } + + return elementsCount - to; + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T predicate) { + return forEach(predicate, 0, size()); + } + + /** + * Applies predicate to a slice of the list, fromIndex, inclusive, to + * toIndex, exclusive, or until predicate returns false. + */ + public > T forEach( + T predicate, int fromIndex, final int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + final KType[] buffer = (KType[]) this.buffer; + for (int i = fromIndex; i < toIndex; i++) { + if (!predicate.apply(buffer[i])) break; + } + + return predicate; + } + + /** + * Create a list from a variable number of arguments or an array of Object. The + * elements are copied from the argument to the internal buffer. + */ + @SafeVarargs + public static ObjectArrayList from(KType... elements) { + final ObjectArrayList list = new ObjectArrayList(elements.length); + list.add(elements); + return list; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectBufferVisualizer.java b/src/main/java/com/carrotsearch/hppc/ObjectBufferVisualizer.java new file mode 100755 index 00000000..c7a988f7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectBufferVisualizer.java @@ -0,0 +1,33 @@ +package com.carrotsearch.hppc; + +/** + * Reused buffer visualization routines. + * + * @see ObjectSet#visualizeKeyDistribution(int) + * @see ObjectVTypeMap#visualizeKeyDistribution(int) + */ +class ObjectBufferVisualizer { + static String visualizeKeyDistribution(Object[] buffer, int max, int characters) { + final StringBuilder b = new StringBuilder(); + final char[] chars = ".123456789X".toCharArray(); + for (int i = 1, start = -1; i <= characters; i++) { + int end = (int) ((long) i * max / characters); + + if (start + 1 <= end) { + int taken = 0; + int slots = 0; + for (int slot = start + 1; slot <= end; slot++, slots++) { + if (!((buffer[slot]) == null)) { + taken++; + } + } + b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]); + start = end; + } + } + while (b.length() < characters) { + b.append(' '); + } + return b.toString(); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectByteAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectByteAssociativeContainer.java new file mode 100755 index 00000000..a5904161 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectByteAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see ObjectContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface ObjectByteAssociativeContainer extends Iterable> { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator> iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(KType key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectBytePredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ObjectByteProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public > T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ObjectBytePredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public > T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public ObjectCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public ByteContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectByteHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectByteHashMap.java new file mode 100755 index 00000000..4de468b8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectByteHashMap.java @@ -0,0 +1,1089 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of Object to byte, implemented using open addressing with + * linear probing for collision resolution. Supports null key. + * + * @see HPPC interfaces diagram + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class ObjectByteHashMap + implements ObjectByteMap, Preallocable, Cloneable, Accountable { + /** The array holding keys. */ + public Object[] keys; + + /** The array holding values. */ + public byte[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public ObjectByteHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectByteHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ObjectByteHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ObjectByteHashMap(ObjectByteAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public byte put(KType key, byte value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == null)) { + byte previousValue = hasEmptyKey ? values[mask + 1] : ((byte) 0); + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + final byte previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return ((byte) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(ObjectByteAssociativeContainer container) { + final int count = size(); + for (ObjectByteCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable> iterable) { + final int count = size(); + for (ObjectByteCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public byte putOrAdd(KType key, byte putValue, byte incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((byte) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public byte addTo(KType key, byte incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public byte remove(KType key) { + final int mask = this.mask; + if (((key) == null)) { + if (!hasEmptyKey) { + return ((byte) 0); + } + hasEmptyKey = false; + byte previousValue = values[mask + 1]; + values[mask + 1] = ((byte) 0); + return previousValue; + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + final byte previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return ((byte) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof ObjectLookupContainer) { + if (hasEmptyKey && other.contains(null)) { + hasEmptyKey = false; + values[mask + 1] = ((byte) 0); + } + + final KType[] keys = (KType[]) this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + KType existing; + if (!((existing = keys[slot]) == null) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (ObjectCursor c : other) { + remove((KType) c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectBytePredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(null, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = ((byte) 0); + } + } + + final KType[] keys = (KType[]) this.keys; + final byte[] values = this.values; + for (int slot = 0; slot <= mask; ) { + KType existing; + if (!((existing = keys[slot]) == null) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(null)) { + hasEmptyKey = false; + values[mask + 1] = ((byte) 0); + } + } + + final KType[] keys = (KType[]) this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + KType existing; + if (!((existing = keys[slot]) == null) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public byte get(KType key) { + if (((key) == null)) { + return hasEmptyKey ? values[mask + 1] : ((byte) 0); + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return ((byte) 0); + } + } + + /** {@inheritDoc} */ + @Override + public byte getOrDefault(KType key, byte defaultValue) { + if (((key) == null)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(KType key) { + if (((key) == null)) { + return hasEmptyKey; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(KType key) { + final int mask = this.mask; + if (((key) == null)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public byte indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public byte indexReplace(int index, byte newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + byte previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, KType key, byte value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == null)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == null); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public byte indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + byte previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = ((byte) 0); + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, null); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (ObjectByteCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** + * Return true if all keys of some other container exist in this container. Equality comparison is + * performed with this object's {@link #equals(Object, Object)} method. + */ + protected boolean equalElements(ObjectByteHashMap other) { + if (other.size() != size()) { + return false; + } + + for (ObjectByteCursor c : other) { + KType key = (KType) c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final KType[] prevKeys = (KType[]) this.keys; + final byte[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final ObjectByteCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new ObjectByteCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectByteCursor fetch() { + final int mask = ObjectByteHashMap.this.mask; + while (index <= mask) { + KType existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = (KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = null; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator> iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T procedure) { + final KType[] keys = (KType[]) this.keys; + final byte[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(null, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == null)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T predicate) { + final KType[] keys = (KType[]) this.keys; + final byte[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(null, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == null)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractObjectCollection + implements ObjectLookupContainer { + private final ObjectByteHashMap owner = ObjectByteHashMap.this; + + @Override + public boolean contains(KType e) { + return owner.containsKey(e); + } + + @Override + public > T forEach(final T procedure) { + owner.forEach((ObjectByteProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public > T forEach(final T predicate) { + owner.forEach((ObjectBytePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator> iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final KType e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator> { + private final ObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new ObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectCursor fetch() { + final int mask = ObjectByteHashMap.this.mask; + while (index <= mask) { + KType existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = (KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = null; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public ByteCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractByteCollection { + private final ObjectByteHashMap owner = ObjectByteHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(byte value) { + for (ObjectByteCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (ObjectByteCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (ObjectByteCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final byte e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final BytePredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ByteCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new ByteCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ByteCursor fetch() { + final int mask = ObjectByteHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!(((KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public ObjectByteHashMap clone() { + try { + + ObjectByteHashMap cloned = (ObjectByteHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (ObjectByteCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return ObjectBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ObjectByteHashMap from(KType[] keys, byte[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ObjectByteHashMap map = new ObjectByteHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(KType key) { + assert !((key) == null); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(KType[] fromKeys, byte[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final KType[] keys = (KType[]) this.keys; + final byte[] values = this.values; + final int mask = this.mask; + KType existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == null)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == null)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + KType[] prevKeys = (KType[]) this.keys; + byte[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = ((KType[]) new Object[arraySize + emptyElementSlot]); + this.values = (new byte[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, KType pendingKey, byte pendingValue) { + assert assigned == resizeAt && (((KType) keys[slot]) == null) && !((pendingKey) == null); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final KType[] prevKeys = (KType[]) this.keys; + final byte[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final KType[] keys = (KType[]) this.keys; + final byte[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final KType existing = keys[slot]; + if (((existing) == null)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = null; + values[gapSlot] = ((byte) 0); + assigned--; + } + + protected boolean equals(Object v1, Object v2) { + return (v1 == v2) || (v1 != null && v1.equals(v2)); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectByteIdentityHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectByteIdentityHashMap.java new file mode 100755 index 00000000..f9567cdd --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectByteIdentityHashMap.java @@ -0,0 +1,71 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +/** An identity hash map of Object to byte. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeIdentityHashMap.java") +public class ObjectByteIdentityHashMap extends ObjectByteHashMap { + /** New instance with sane defaults. */ + public ObjectByteIdentityHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectByteIdentityHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ObjectByteIdentityHashMap(int expectedElements, double loadFactor) { + super(expectedElements, loadFactor); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ObjectByteIdentityHashMap(ObjectByteAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + @Override + public int hashKey(KType key) { + assert !((key) == null); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(System.identityHashCode(key)); + } + + @Override + public boolean equals(Object v1, Object v2) { + return v1 == v2; + } + + @SuppressWarnings("unchecked") + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ObjectByteIdentityHashMap from(KType[] keys, byte[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ObjectByteIdentityHashMap map = new ObjectByteIdentityHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectByteMap.java b/src/main/java/com/carrotsearch/hppc/ObjectByteMap.java new file mode 100755 index 00000000..9b4ac38a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectByteMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ObjectByteCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface ObjectByteMap extends ObjectByteAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public byte get(KType key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public byte getOrDefault(KType key, byte defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public byte put(KType key, byte value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(KType key, byte value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(ObjectByteAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable> iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public byte putOrAdd(KType key, byte putValue, byte incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public byte addTo(KType key, byte additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public byte remove(KType key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link ObjectByteMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(KType key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public byte indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public byte indexReplace(int index, byte newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, KType key, byte value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public byte indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectCharAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectCharAssociativeContainer.java new file mode 100755 index 00000000..fc06ba23 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectCharAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see ObjectContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface ObjectCharAssociativeContainer extends Iterable> { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator> iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(KType key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectCharPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ObjectCharProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public > T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ObjectCharPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public > T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public ObjectCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public CharContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectCharHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectCharHashMap.java new file mode 100755 index 00000000..b71d892c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectCharHashMap.java @@ -0,0 +1,1089 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of Object to char, implemented using open addressing with + * linear probing for collision resolution. Supports null key. + * + * @see HPPC interfaces diagram + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class ObjectCharHashMap + implements ObjectCharMap, Preallocable, Cloneable, Accountable { + /** The array holding keys. */ + public Object[] keys; + + /** The array holding values. */ + public char[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public ObjectCharHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectCharHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ObjectCharHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ObjectCharHashMap(ObjectCharAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public char put(KType key, char value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == null)) { + char previousValue = hasEmptyKey ? values[mask + 1] : ((char) 0); + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + final char previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return ((char) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(ObjectCharAssociativeContainer container) { + final int count = size(); + for (ObjectCharCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable> iterable) { + final int count = size(); + for (ObjectCharCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public char putOrAdd(KType key, char putValue, char incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((char) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public char addTo(KType key, char incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public char remove(KType key) { + final int mask = this.mask; + if (((key) == null)) { + if (!hasEmptyKey) { + return ((char) 0); + } + hasEmptyKey = false; + char previousValue = values[mask + 1]; + values[mask + 1] = ((char) 0); + return previousValue; + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + final char previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return ((char) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof ObjectLookupContainer) { + if (hasEmptyKey && other.contains(null)) { + hasEmptyKey = false; + values[mask + 1] = ((char) 0); + } + + final KType[] keys = (KType[]) this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + KType existing; + if (!((existing = keys[slot]) == null) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (ObjectCursor c : other) { + remove((KType) c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectCharPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(null, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = ((char) 0); + } + } + + final KType[] keys = (KType[]) this.keys; + final char[] values = this.values; + for (int slot = 0; slot <= mask; ) { + KType existing; + if (!((existing = keys[slot]) == null) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(null)) { + hasEmptyKey = false; + values[mask + 1] = ((char) 0); + } + } + + final KType[] keys = (KType[]) this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + KType existing; + if (!((existing = keys[slot]) == null) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public char get(KType key) { + if (((key) == null)) { + return hasEmptyKey ? values[mask + 1] : ((char) 0); + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return ((char) 0); + } + } + + /** {@inheritDoc} */ + @Override + public char getOrDefault(KType key, char defaultValue) { + if (((key) == null)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(KType key) { + if (((key) == null)) { + return hasEmptyKey; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(KType key) { + final int mask = this.mask; + if (((key) == null)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public char indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public char indexReplace(int index, char newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + char previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, KType key, char value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == null)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == null); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public char indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + char previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = ((char) 0); + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, null); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (ObjectCharCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** + * Return true if all keys of some other container exist in this container. Equality comparison is + * performed with this object's {@link #equals(Object, Object)} method. + */ + protected boolean equalElements(ObjectCharHashMap other) { + if (other.size() != size()) { + return false; + } + + for (ObjectCharCursor c : other) { + KType key = (KType) c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final KType[] prevKeys = (KType[]) this.keys; + final char[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final ObjectCharCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new ObjectCharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectCharCursor fetch() { + final int mask = ObjectCharHashMap.this.mask; + while (index <= mask) { + KType existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = (KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = null; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator> iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T procedure) { + final KType[] keys = (KType[]) this.keys; + final char[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(null, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == null)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T predicate) { + final KType[] keys = (KType[]) this.keys; + final char[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(null, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == null)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractObjectCollection + implements ObjectLookupContainer { + private final ObjectCharHashMap owner = ObjectCharHashMap.this; + + @Override + public boolean contains(KType e) { + return owner.containsKey(e); + } + + @Override + public > T forEach(final T procedure) { + owner.forEach((ObjectCharProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public > T forEach(final T predicate) { + owner.forEach((ObjectCharPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator> iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final KType e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator> { + private final ObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new ObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectCursor fetch() { + final int mask = ObjectCharHashMap.this.mask; + while (index <= mask) { + KType existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = (KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = null; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public CharCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractCharCollection { + private final ObjectCharHashMap owner = ObjectCharHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(char value) { + for (ObjectCharCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (ObjectCharCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (ObjectCharCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final char e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final CharPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final CharCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new CharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharCursor fetch() { + final int mask = ObjectCharHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!(((KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public ObjectCharHashMap clone() { + try { + + ObjectCharHashMap cloned = (ObjectCharHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (ObjectCharCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return ObjectBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ObjectCharHashMap from(KType[] keys, char[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ObjectCharHashMap map = new ObjectCharHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(KType key) { + assert !((key) == null); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(KType[] fromKeys, char[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final KType[] keys = (KType[]) this.keys; + final char[] values = this.values; + final int mask = this.mask; + KType existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == null)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == null)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + KType[] prevKeys = (KType[]) this.keys; + char[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = ((KType[]) new Object[arraySize + emptyElementSlot]); + this.values = (new char[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, KType pendingKey, char pendingValue) { + assert assigned == resizeAt && (((KType) keys[slot]) == null) && !((pendingKey) == null); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final KType[] prevKeys = (KType[]) this.keys; + final char[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final KType[] keys = (KType[]) this.keys; + final char[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final KType existing = keys[slot]; + if (((existing) == null)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = null; + values[gapSlot] = ((char) 0); + assigned--; + } + + protected boolean equals(Object v1, Object v2) { + return (v1 == v2) || (v1 != null && v1.equals(v2)); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectCharIdentityHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectCharIdentityHashMap.java new file mode 100755 index 00000000..d373e7f0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectCharIdentityHashMap.java @@ -0,0 +1,71 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +/** An identity hash map of Object to char. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeIdentityHashMap.java") +public class ObjectCharIdentityHashMap extends ObjectCharHashMap { + /** New instance with sane defaults. */ + public ObjectCharIdentityHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectCharIdentityHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ObjectCharIdentityHashMap(int expectedElements, double loadFactor) { + super(expectedElements, loadFactor); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ObjectCharIdentityHashMap(ObjectCharAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + @Override + public int hashKey(KType key) { + assert !((key) == null); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(System.identityHashCode(key)); + } + + @Override + public boolean equals(Object v1, Object v2) { + return v1 == v2; + } + + @SuppressWarnings("unchecked") + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ObjectCharIdentityHashMap from(KType[] keys, char[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ObjectCharIdentityHashMap map = new ObjectCharIdentityHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectCharMap.java b/src/main/java/com/carrotsearch/hppc/ObjectCharMap.java new file mode 100755 index 00000000..ab636b51 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectCharMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ObjectCharCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface ObjectCharMap extends ObjectCharAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public char get(KType key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public char getOrDefault(KType key, char defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public char put(KType key, char value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(KType key, char value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(ObjectCharAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable> iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public char putOrAdd(KType key, char putValue, char incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public char addTo(KType key, char additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public char remove(KType key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link ObjectCharMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(KType key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public char indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public char indexReplace(int index, char newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, KType key, char value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public char indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectCollection.java b/src/main/java/com/carrotsearch/hppc/ObjectCollection.java new file mode 100755 index 00000000..447e46de --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectCollection.java @@ -0,0 +1,64 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.predicates.ObjectPredicate; + +/** + * A collection allows basic, efficient operations on sets of elements (difference and + * intersection). + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java") +public interface ObjectCollection extends ObjectContainer { + /** + * Removes all occurrences of e from this collection. + * + * @param e Element to be removed from this collection, if present. + * @return The number of removed elements as a result of this call. + */ + public int removeAll(KType e); + + /** + * Removes all elements in this collection that are present in c. + * + * @return Returns the number of removed elements. + */ + public int removeAll(ObjectLookupContainer c); + + /** + * Removes all elements in this collection for which the given predicate returns true + * . + * + * @return Returns the number of removed elements. + */ + public int removeAll(ObjectPredicate predicate); + + /** + * Keeps all elements in this collection that are present in c. Runs in time + * proportional to the number of elements in this collection. Equivalent of sets intersection. + * + * @return Returns the number of removed elements. + */ + public int retainAll(ObjectLookupContainer c); + + /** + * Keeps all elements in this collection for which the given predicate returns true. + * + * @return Returns the number of removed elements. + */ + public int retainAll(ObjectPredicate predicate); + + /** + * Removes all elements from this collection. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectContainer.java new file mode 100755 index 00000000..6e8cd488 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectContainer.java @@ -0,0 +1,85 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ObjectCursor; +import com.carrotsearch.hppc.predicates.ObjectPredicate; +import com.carrotsearch.hppc.procedures.ObjectProcedure; +import java.util.Iterator; + +/** A generic container holding Objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java") +public interface ObjectContainer extends Iterable> { + /** + * Returns an iterator to a cursor traversing the collection. The order of traversal is not + * defined. More than one cursor may be active at a time. The behavior of iterators is undefined + * if structural changes are made to the underlying collection. + * + *

The iterator is implemented as a cursor and it returns the same cursor instance on + * every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current + * list's value (or index in the list) use the cursor's public fields. An example is shown below. + * + *

+   * for (ObjectCursor<Object> c : container) {
+   *   System.out.println("index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator> iterator(); + + /** + * Lookup a given element in the container. This operation has no speed guarantees (may be linear + * with respect to the size of this container). + * + * @return Returns true if this container has an element equal to e. + */ + public boolean contains(KType e); + + /** + * Return the current number of elements in this container. The time for calculating the + * container's size may take O(n) time, although implementing classes should try to + * maintain the current size and return in constant time. + */ + public int size(); + + /** Shortcut for size() == 0. */ + public boolean isEmpty(); + + /** + * Copies all elements of this container to an array. + * + *

The returned array is always a copy, regardless of the storage used by the container. + */ + public Object[] toArray(); + + /** + * Copies all elements of this container to a dynamically created array of the given component + * type. + * + * @throws ArrayStoreException Thrown if this container's elements are not assignable to the + * array's component type. + */ + public T[] toArray(Class componentClass); + + /** + * Applies a procedure to all container elements. Returns the argument (any subclass + * of {@link ObjectProcedure}. This lets the caller to call methods of the argument by chaining + * the call (even if the argument is an anonymous type) to retrieve computed values, for example + * (IntContainer): + * + *

+   * int count = container.forEach(new IntProcedure() {
+   *   int count; // this is a field declaration in an anonymous class.
+   *
+   *   public void apply(int value) {
+   *     count++;
+   *   }
+   * }).count;
+   * 
+ */ + public > T forEach(T procedure); + + /** + * Applies a predicate to container elements as long, as the predicate returns + * true. The iteration is interrupted otherwise. + */ + public > T forEach(T predicate); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectDeque.java b/src/main/java/com/carrotsearch/hppc/ObjectDeque.java new file mode 100755 index 00000000..2e6f62f3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectDeque.java @@ -0,0 +1,77 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ObjectCursor; +import com.carrotsearch.hppc.predicates.ObjectPredicate; +import com.carrotsearch.hppc.procedures.ObjectProcedure; +import java.util.Deque; +import java.util.Iterator; + +/** + * A linear collection that supports element insertion and removal at both ends. + * + * @see Deque + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java") +public interface ObjectDeque extends ObjectCollection { + /** + * Removes the first element that equals e. + * + * @return The deleted element's index or -1 if the element was not found. + */ + public int removeFirst(KType e); + + /** + * Removes the last element that equals e. + * + * @return The deleted element's index or -1 if the element was not found. + */ + public int removeLast(KType e); + + /** Inserts the specified element at the front of this deque. */ + public void addFirst(KType e); + + /** Inserts the specified element at the end of this deque. */ + public void addLast(KType e); + + /** + * Retrieves and removes the first element of this deque. + * + * @return the head (first) element of this deque. + */ + public KType removeFirst(); + + /** + * Retrieves and removes the last element of this deque. + * + * @return the tail of this deque. + */ + public KType removeLast(); + + /** + * Retrieves the first element of this deque but does not remove it. + * + * @return the head of this deque. + */ + public KType getFirst(); + + /** + * Retrieves the last element of this deque but does not remove it. + * + * @return the head of this deque. + */ + public KType getLast(); + + /** + * @return An iterator over elements in this deque in tail-to-head order. + */ + public Iterator> descendingIterator(); + + /** Applies a procedure to all elements in tail-to-head order. */ + public > T descendingForEach(T procedure); + + /** + * Applies a predicate to container elements as long, as the predicate returns + * true. The iteration is interrupted otherwise. + */ + public > T descendingForEach(T predicate); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectDoubleAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectDoubleAssociativeContainer.java new file mode 100755 index 00000000..0eb15e2a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectDoubleAssociativeContainer.java @@ -0,0 +1,106 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see ObjectContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface ObjectDoubleAssociativeContainer + extends Iterable> { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *
+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator> iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(KType key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectDoublePredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ObjectDoubleProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public > T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ObjectDoublePredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public > T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public ObjectCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public DoubleContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectDoubleHashMap.java new file mode 100755 index 00000000..bf3240c7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectDoubleHashMap.java @@ -0,0 +1,1091 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of Object to double, implemented using open addressing with + * linear probing for collision resolution. Supports null key. + * + * @see HPPC interfaces diagram + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class ObjectDoubleHashMap + implements ObjectDoubleMap, Preallocable, Cloneable, Accountable { + /** The array holding keys. */ + public Object[] keys; + + /** The array holding values. */ + public double[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public ObjectDoubleHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectDoubleHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ObjectDoubleHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ObjectDoubleHashMap(ObjectDoubleAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public double put(KType key, double value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == null)) { + double previousValue = hasEmptyKey ? values[mask + 1] : 0d; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + final double previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0d; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(ObjectDoubleAssociativeContainer container) { + final int count = size(); + for (ObjectDoubleCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable> iterable) { + final int count = size(); + for (ObjectDoubleCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public double putOrAdd(KType key, double putValue, double incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((double) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public double addTo(KType key, double incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public double remove(KType key) { + final int mask = this.mask; + if (((key) == null)) { + if (!hasEmptyKey) { + return 0d; + } + hasEmptyKey = false; + double previousValue = values[mask + 1]; + values[mask + 1] = 0d; + return previousValue; + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + final double previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0d; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof ObjectLookupContainer) { + if (hasEmptyKey && other.contains(null)) { + hasEmptyKey = false; + values[mask + 1] = 0d; + } + + final KType[] keys = (KType[]) this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + KType existing; + if (!((existing = keys[slot]) == null) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (ObjectCursor c : other) { + remove((KType) c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectDoublePredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(null, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0d; + } + } + + final KType[] keys = (KType[]) this.keys; + final double[] values = this.values; + for (int slot = 0; slot <= mask; ) { + KType existing; + if (!((existing = keys[slot]) == null) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(null)) { + hasEmptyKey = false; + values[mask + 1] = 0d; + } + } + + final KType[] keys = (KType[]) this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + KType existing; + if (!((existing = keys[slot]) == null) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public double get(KType key) { + if (((key) == null)) { + return hasEmptyKey ? values[mask + 1] : 0d; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0d; + } + } + + /** {@inheritDoc} */ + @Override + public double getOrDefault(KType key, double defaultValue) { + if (((key) == null)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(KType key) { + if (((key) == null)) { + return hasEmptyKey; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(KType key) { + final int mask = this.mask; + if (((key) == null)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public double indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public double indexReplace(int index, double newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + double previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, KType key, double value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == null)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == null); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public double indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + double previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0d; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, null); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (ObjectDoubleCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** + * Return true if all keys of some other container exist in this container. Equality comparison is + * performed with this object's {@link #equals(Object, Object)} method. + */ + protected boolean equalElements(ObjectDoubleHashMap other) { + if (other.size() != size()) { + return false; + } + + for (ObjectDoubleCursor c : other) { + KType key = (KType) c.key; + if (!containsKey(key) + || !(Double.doubleToLongBits(c.value) == Double.doubleToLongBits(get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final KType[] prevKeys = (KType[]) this.keys; + final double[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final ObjectDoubleCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new ObjectDoubleCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectDoubleCursor fetch() { + final int mask = ObjectDoubleHashMap.this.mask; + while (index <= mask) { + KType existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = (KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = null; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator> iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T procedure) { + final KType[] keys = (KType[]) this.keys; + final double[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(null, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == null)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T predicate) { + final KType[] keys = (KType[]) this.keys; + final double[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(null, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == null)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractObjectCollection + implements ObjectLookupContainer { + private final ObjectDoubleHashMap owner = ObjectDoubleHashMap.this; + + @Override + public boolean contains(KType e) { + return owner.containsKey(e); + } + + @Override + public > T forEach(final T procedure) { + owner.forEach((ObjectDoubleProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public > T forEach(final T predicate) { + owner.forEach((ObjectDoublePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator> iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final KType e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator> { + private final ObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new ObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectCursor fetch() { + final int mask = ObjectDoubleHashMap.this.mask; + while (index <= mask) { + KType existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = (KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = null; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public DoubleCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractDoubleCollection { + private final ObjectDoubleHashMap owner = ObjectDoubleHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(double value) { + for (ObjectDoubleCursor c : owner) { + if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (ObjectDoubleCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (ObjectDoubleCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final double e) { + return owner.removeAll( + (key, value) -> (Double.doubleToLongBits(e) == Double.doubleToLongBits(value))); + } + + @Override + public int removeAll(final DoublePredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final DoubleCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new DoubleCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected DoubleCursor fetch() { + final int mask = ObjectDoubleHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!(((KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public ObjectDoubleHashMap clone() { + try { + + ObjectDoubleHashMap cloned = (ObjectDoubleHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (ObjectDoubleCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return ObjectBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ObjectDoubleHashMap from(KType[] keys, double[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ObjectDoubleHashMap map = new ObjectDoubleHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(KType key) { + assert !((key) == null); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(KType[] fromKeys, double[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final KType[] keys = (KType[]) this.keys; + final double[] values = this.values; + final int mask = this.mask; + KType existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == null)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == null)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + KType[] prevKeys = (KType[]) this.keys; + double[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = ((KType[]) new Object[arraySize + emptyElementSlot]); + this.values = (new double[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, KType pendingKey, double pendingValue) { + assert assigned == resizeAt && (((KType) keys[slot]) == null) && !((pendingKey) == null); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final KType[] prevKeys = (KType[]) this.keys; + final double[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final KType[] keys = (KType[]) this.keys; + final double[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final KType existing = keys[slot]; + if (((existing) == null)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = null; + values[gapSlot] = 0d; + assigned--; + } + + protected boolean equals(Object v1, Object v2) { + return (v1 == v2) || (v1 != null && v1.equals(v2)); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectDoubleIdentityHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectDoubleIdentityHashMap.java new file mode 100755 index 00000000..b034adf4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectDoubleIdentityHashMap.java @@ -0,0 +1,71 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +/** An identity hash map of Object to double. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeIdentityHashMap.java") +public class ObjectDoubleIdentityHashMap extends ObjectDoubleHashMap { + /** New instance with sane defaults. */ + public ObjectDoubleIdentityHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectDoubleIdentityHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ObjectDoubleIdentityHashMap(int expectedElements, double loadFactor) { + super(expectedElements, loadFactor); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ObjectDoubleIdentityHashMap(ObjectDoubleAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + @Override + public int hashKey(KType key) { + assert !((key) == null); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(System.identityHashCode(key)); + } + + @Override + public boolean equals(Object v1, Object v2) { + return v1 == v2; + } + + @SuppressWarnings("unchecked") + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ObjectDoubleIdentityHashMap from(KType[] keys, double[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ObjectDoubleIdentityHashMap map = new ObjectDoubleIdentityHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectDoubleMap.java b/src/main/java/com/carrotsearch/hppc/ObjectDoubleMap.java new file mode 100755 index 00000000..595fc978 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectDoubleMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ObjectDoubleCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface ObjectDoubleMap extends ObjectDoubleAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public double get(KType key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public double getOrDefault(KType key, double defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public double put(KType key, double value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(KType key, double value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(ObjectDoubleAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable> iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public double putOrAdd(KType key, double putValue, double incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public double addTo(KType key, double additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public double remove(KType key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link ObjectDoubleMap} and both objects contains exactly the + * same key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(KType key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public double indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public double indexReplace(int index, double newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, KType key, double value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public double indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectFloatAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectFloatAssociativeContainer.java new file mode 100755 index 00000000..a7448b25 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectFloatAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see ObjectContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface ObjectFloatAssociativeContainer extends Iterable> { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator> iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(KType key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectFloatPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ObjectFloatProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public > T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ObjectFloatPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public > T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public ObjectCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public FloatContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectFloatHashMap.java new file mode 100755 index 00000000..2dc4c98e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectFloatHashMap.java @@ -0,0 +1,1090 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of Object to float, implemented using open addressing with + * linear probing for collision resolution. Supports null key. + * + * @see HPPC interfaces diagram + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class ObjectFloatHashMap + implements ObjectFloatMap, Preallocable, Cloneable, Accountable { + /** The array holding keys. */ + public Object[] keys; + + /** The array holding values. */ + public float[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public ObjectFloatHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectFloatHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ObjectFloatHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ObjectFloatHashMap(ObjectFloatAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public float put(KType key, float value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == null)) { + float previousValue = hasEmptyKey ? values[mask + 1] : 0f; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + final float previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0f; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(ObjectFloatAssociativeContainer container) { + final int count = size(); + for (ObjectFloatCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable> iterable) { + final int count = size(); + for (ObjectFloatCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public float putOrAdd(KType key, float putValue, float incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((float) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public float addTo(KType key, float incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public float remove(KType key) { + final int mask = this.mask; + if (((key) == null)) { + if (!hasEmptyKey) { + return 0f; + } + hasEmptyKey = false; + float previousValue = values[mask + 1]; + values[mask + 1] = 0f; + return previousValue; + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + final float previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0f; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof ObjectLookupContainer) { + if (hasEmptyKey && other.contains(null)) { + hasEmptyKey = false; + values[mask + 1] = 0f; + } + + final KType[] keys = (KType[]) this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + KType existing; + if (!((existing = keys[slot]) == null) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (ObjectCursor c : other) { + remove((KType) c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectFloatPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(null, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0f; + } + } + + final KType[] keys = (KType[]) this.keys; + final float[] values = this.values; + for (int slot = 0; slot <= mask; ) { + KType existing; + if (!((existing = keys[slot]) == null) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(null)) { + hasEmptyKey = false; + values[mask + 1] = 0f; + } + } + + final KType[] keys = (KType[]) this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + KType existing; + if (!((existing = keys[slot]) == null) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public float get(KType key) { + if (((key) == null)) { + return hasEmptyKey ? values[mask + 1] : 0f; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0f; + } + } + + /** {@inheritDoc} */ + @Override + public float getOrDefault(KType key, float defaultValue) { + if (((key) == null)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(KType key) { + if (((key) == null)) { + return hasEmptyKey; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(KType key) { + final int mask = this.mask; + if (((key) == null)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public float indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public float indexReplace(int index, float newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + float previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, KType key, float value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == null)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == null); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public float indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + float previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0f; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, null); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (ObjectFloatCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** + * Return true if all keys of some other container exist in this container. Equality comparison is + * performed with this object's {@link #equals(Object, Object)} method. + */ + protected boolean equalElements(ObjectFloatHashMap other) { + if (other.size() != size()) { + return false; + } + + for (ObjectFloatCursor c : other) { + KType key = (KType) c.key; + if (!containsKey(key) || !(Float.floatToIntBits(c.value) == Float.floatToIntBits(get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final KType[] prevKeys = (KType[]) this.keys; + final float[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final ObjectFloatCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new ObjectFloatCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectFloatCursor fetch() { + final int mask = ObjectFloatHashMap.this.mask; + while (index <= mask) { + KType existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = (KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = null; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator> iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T procedure) { + final KType[] keys = (KType[]) this.keys; + final float[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(null, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == null)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T predicate) { + final KType[] keys = (KType[]) this.keys; + final float[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(null, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == null)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractObjectCollection + implements ObjectLookupContainer { + private final ObjectFloatHashMap owner = ObjectFloatHashMap.this; + + @Override + public boolean contains(KType e) { + return owner.containsKey(e); + } + + @Override + public > T forEach(final T procedure) { + owner.forEach((ObjectFloatProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public > T forEach(final T predicate) { + owner.forEach((ObjectFloatPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator> iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final KType e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator> { + private final ObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new ObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectCursor fetch() { + final int mask = ObjectFloatHashMap.this.mask; + while (index <= mask) { + KType existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = (KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = null; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public FloatCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractFloatCollection { + private final ObjectFloatHashMap owner = ObjectFloatHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(float value) { + for (ObjectFloatCursor c : owner) { + if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (ObjectFloatCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (ObjectFloatCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final float e) { + return owner.removeAll( + (key, value) -> (Float.floatToIntBits(e) == Float.floatToIntBits(value))); + } + + @Override + public int removeAll(final FloatPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final FloatCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new FloatCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected FloatCursor fetch() { + final int mask = ObjectFloatHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!(((KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public ObjectFloatHashMap clone() { + try { + + ObjectFloatHashMap cloned = (ObjectFloatHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (ObjectFloatCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return ObjectBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ObjectFloatHashMap from(KType[] keys, float[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ObjectFloatHashMap map = new ObjectFloatHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(KType key) { + assert !((key) == null); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(KType[] fromKeys, float[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final KType[] keys = (KType[]) this.keys; + final float[] values = this.values; + final int mask = this.mask; + KType existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == null)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == null)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + KType[] prevKeys = (KType[]) this.keys; + float[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = ((KType[]) new Object[arraySize + emptyElementSlot]); + this.values = (new float[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, KType pendingKey, float pendingValue) { + assert assigned == resizeAt && (((KType) keys[slot]) == null) && !((pendingKey) == null); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final KType[] prevKeys = (KType[]) this.keys; + final float[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final KType[] keys = (KType[]) this.keys; + final float[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final KType existing = keys[slot]; + if (((existing) == null)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = null; + values[gapSlot] = 0f; + assigned--; + } + + protected boolean equals(Object v1, Object v2) { + return (v1 == v2) || (v1 != null && v1.equals(v2)); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectFloatIdentityHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectFloatIdentityHashMap.java new file mode 100755 index 00000000..cfb63d0c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectFloatIdentityHashMap.java @@ -0,0 +1,71 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +/** An identity hash map of Object to float. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeIdentityHashMap.java") +public class ObjectFloatIdentityHashMap extends ObjectFloatHashMap { + /** New instance with sane defaults. */ + public ObjectFloatIdentityHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectFloatIdentityHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ObjectFloatIdentityHashMap(int expectedElements, double loadFactor) { + super(expectedElements, loadFactor); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ObjectFloatIdentityHashMap(ObjectFloatAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + @Override + public int hashKey(KType key) { + assert !((key) == null); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(System.identityHashCode(key)); + } + + @Override + public boolean equals(Object v1, Object v2) { + return v1 == v2; + } + + @SuppressWarnings("unchecked") + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ObjectFloatIdentityHashMap from(KType[] keys, float[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ObjectFloatIdentityHashMap map = new ObjectFloatIdentityHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectFloatMap.java b/src/main/java/com/carrotsearch/hppc/ObjectFloatMap.java new file mode 100755 index 00000000..8feee948 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectFloatMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ObjectFloatCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface ObjectFloatMap extends ObjectFloatAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public float get(KType key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public float getOrDefault(KType key, float defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public float put(KType key, float value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(KType key, float value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(ObjectFloatAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable> iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public float putOrAdd(KType key, float putValue, float incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public float addTo(KType key, float additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public float remove(KType key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link ObjectFloatMap} and both objects contains exactly the + * same key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(KType key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public float indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public float indexReplace(int index, float newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, KType key, float value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public float indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectHashSet.java b/src/main/java/com/carrotsearch/hppc/ObjectHashSet.java new file mode 100755 index 00000000..1a37b23e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectHashSet.java @@ -0,0 +1,797 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash set of Objects, implemented using open addressing with linear probing for + * collision resolution. + * + * @see HPPC interfaces diagram + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeHashSet.java") +public class ObjectHashSet extends AbstractObjectCollection + implements ObjectLookupContainer, + ObjectSet, + Preallocable, + Cloneable, + Accountable { + /** The hash array holding keys. */ + public Object[] keys; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any. + * + * @see #size() + * @see #hasEmptyKey + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** + * New instance with sane defaults. + * + * @see #ObjectHashSet(int, double) + */ + public ObjectHashSet() { + this(DEFAULT_EXPECTED_ELEMENTS, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with sane defaults. + * + * @see #ObjectHashSet(int, double) + */ + public ObjectHashSet(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ObjectHashSet(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** New instance copying elements from another {@link ObjectContainer}. */ + public ObjectHashSet(ObjectContainer container) { + this(container.size()); + addAll(container); + } + + /** {@inheritDoc} */ + @Override + public boolean add(KType key) { + if (((key) == null)) { + assert ((keys[mask + 1]) == null); + boolean added = !hasEmptyKey; + hasEmptyKey = true; + return added; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return false; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key); + } else { + keys[slot] = key; + } + + assigned++; + return true; + } + } + + /** + * Adds all elements from the given list (vararg) to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + */ + @SafeVarargs + public final int addAll(KType... elements) { + ensureCapacity(elements.length); + int count = 0; + for (KType e : elements) { + if (add(e)) { + count++; + } + } + return count; + } + + /** + * Adds all elements from the given {@link ObjectContainer} to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + */ + public int addAll(ObjectContainer container) { + ensureCapacity(container.size()); + return addAll((Iterable>) container); + } + + /** + * Adds all elements from the given iterable to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + */ + public int addAll(Iterable> iterable) { + int count = 0; + for (ObjectCursor cursor : iterable) { + if (add(cursor.value)) { + count++; + } + } + return count; + } + + /** {@inheritDoc} */ + @Override + public Object[] toArray() { + + final KType[] cloned = ((KType[]) new Object[size()]); + int j = 0; + if (hasEmptyKey) { + cloned[j++] = null; + } + + final KType[] keys = (KType[]) this.keys; + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + KType existing; + if (!((existing = keys[slot]) == null)) { + cloned[j++] = existing; + } + } + + return cloned; + } + + /** An alias for the (preferred) {@link #removeAll}. */ + public boolean remove(KType key) { + if (((key) == null)) { + boolean hadEmptyKey = hasEmptyKey; + hasEmptyKey = false; + return hadEmptyKey; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + shiftConflictingKeys(slot); + return true; + } + slot = (slot + 1) & mask; + } + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(KType key) { + return remove(key) ? 1 : 0; + } + + /** + * Removes all keys present in a given container. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectContainer other) { + final int before = size(); + + // Try to iterate over the smaller set or over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof ObjectLookupContainer) { + if (hasEmptyKey && other.contains(null)) { + hasEmptyKey = false; + } + + final KType[] keys = (KType[]) this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + KType existing; + if (!((existing = keys[slot]) == null) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (ObjectCursor c : other) { + remove((KType) c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectPredicate predicate) { + int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(null)) { + hasEmptyKey = false; + } + } + + final KType[] keys = (KType[]) this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + KType existing; + if (!((existing = keys[slot]) == null)) { + if (predicate.apply(existing)) { + shiftConflictingKeys(slot); + continue; // Repeat the check for the same slot i (shifted). + } + } + slot++; + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public boolean contains(KType key) { + if (((key) == null)) { + return hasEmptyKey; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return true; + } + slot = (slot + 1) & mask; + } + return false; + } + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + Arrays.fill(keys, null); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + keys = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return size() == 0; + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final KType[] prevKeys = (KType[]) this.keys; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys); + } + } + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + final KType[] keys = (KType[]) this.keys; + for (int slot = mask; slot >= 0; slot--) { + KType existing; + if (!((existing = keys[slot]) == null)) { + h += BitMixer.mix(existing); + } + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && sameKeys(getClass().cast(obj))); + } + + /** + * Return true if all keys of some other container exist in this container. Equality comparison is + * performed with this object's {@link #equals(Object, Object)} method. + */ + private boolean sameKeys(ObjectSet other) { + if (other.size() != size()) { + return false; + } + + for (ObjectCursor c : other) { + if (!contains((KType) c.value)) { + return false; + } + } + + return true; + } + + /** {@inheritDoc} */ + @Override + public ObjectHashSet clone() { + try { + + ObjectHashSet cloned = (ObjectHashSet) super.clone(); + cloned.keys = keys.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator> iterator() { + return new EntryIterator(); + } + + @Override + public long ramBytesAllocated() { + // int: assigned, mask, keyMixer, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys); + } + + @Override + public long ramBytesUsed() { + // int: assigned, mask, keyMixer, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + protected final class EntryIterator extends AbstractIterator> { + private final ObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new ObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectCursor fetch() { + final int mask = ObjectHashSet.this.mask; + while (index <= mask) { + KType existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = (KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = null; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T procedure) { + if (hasEmptyKey) { + procedure.apply(null); + } + + final KType[] keys = (KType[]) this.keys; + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + KType existing; + if (!((existing = keys[slot]) == null)) { + procedure.apply(existing); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T predicate) { + if (hasEmptyKey) { + if (!predicate.apply(null)) { + return predicate; + } + } + + final KType[] keys = (KType[]) this.keys; + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + KType existing; + if (!((existing = keys[slot]) == null)) { + if (!predicate.apply(existing)) { + break; + } + } + } + + return predicate; + } + + /** + * Create a set from a variable number of arguments or an array of Object. The + * elements are copied from the argument to the internal buffer. + */ + @SafeVarargs + public static ObjectHashSet from(KType... elements) { + final ObjectHashSet set = new ObjectHashSet(elements.length); + set.addAll(elements); + return set; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(KType key) { + assert !((key) == null); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up logic in + * certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between modifications (it will not be affected by read-only + * operations). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the set. + * @return A non-negative value of the logical "index" of the key in the set or a negative value + * if the key did not exist. + */ + public int indexOf(KType key) { + final int mask = this.mask; + if (((key) == null)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index) { + assert index < 0 || index <= mask || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** + * Returns the exact value of the existing key. This method makes sense for sets of objects which + * define custom key-equality relationship. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the equivalent key currently stored in the set. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public KType indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return (KType) keys[index]; + } + + /** + * Replaces the existing equivalent key with the given one and returns any previous value stored + * for that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @param equivalentKey The key to put in the set as a replacement. Must be equivalent to the key + * currently stored at the provided index. + * @return Returns the previous key stored in the set. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public KType indexReplace(int index, KType equivalentKey) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + assert this.equals(keys[index], equivalentKey); + + KType previousValue = (KType) keys[index]; + keys[index] = equivalentKey; + return previousValue; + } + + /** + * Inserts a key for an index that is not present in the set. This method may help in avoiding + * double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public void indexInsert(int index, KType key) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == null)) { + assert index == mask + 1; + assert ((keys[index]) == null); + hasEmptyKey = true; + } else { + assert ((keys[index]) == null); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key); + } else { + keys[index] = key; + } + + assigned++; + } + } + + /** + * Removes a key at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public void indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + if (index > mask) { + hasEmptyKey = false; + } else { + shiftConflictingKeys(index); + } + } + + @Override + public String visualizeKeyDistribution(int characters) { + return ObjectBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(KType[] fromKeys) { + assert HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored keys into the new buffers. + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + KType existing; + for (int i = fromKeys.length - 1; --i >= 0; ) { + if (!((existing = fromKeys[i]) == null)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == null)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + KType[] prevKeys = (KType[]) this.keys; + try { + int emptyElementSlot = 1; + this.keys = ((KType[]) new Object[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.keys == null ? 0 : size(), arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key to be inserted into the buffer but there is not + * enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, KType pendingKey) { + assert assigned == resizeAt && (((KType) keys[slot]) == null) && !((pendingKey) == null); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final KType[] prevKeys = (KType[]) this.keys; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + + // Rehash old keys, including the pending key. + rehash(prevKeys); + } + + /** Shift all the slot-conflicting keys allocated to (and including) slot. */ + protected void shiftConflictingKeys(int gapSlot) { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final KType existing = keys[slot]; + if (((existing) == null)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = null; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectIdentityHashSet.java b/src/main/java/com/carrotsearch/hppc/ObjectIdentityHashSet.java new file mode 100755 index 00000000..4efb528d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectIdentityHashSet.java @@ -0,0 +1,66 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +/** A reference-equality (identity) hash set. */ +public class ObjectIdentityHashSet extends ObjectHashSet { + /** New instance with sane defaults. */ + public ObjectIdentityHashSet() { + this(DEFAULT_EXPECTED_ELEMENTS, DEFAULT_LOAD_FACTOR); + } + + /** New instance with sane defaults. */ + public ObjectIdentityHashSet(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ObjectIdentityHashSet(int expectedElements, double loadFactor) { + super(expectedElements, loadFactor); + } + + /** New instance copying elements from another {@link ObjectContainer}. */ + public ObjectIdentityHashSet(ObjectContainer container) { + this(container.size()); + addAll(container); + } + + @Override + protected int hashKey(KType key) { + assert key != null; // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(System.identityHashCode(key)); + } + + @Override + protected boolean equals(Object v1, Object v2) { + return v1 == v2; + } + + /** + * Create a set from a variable number of arguments or an array of KType. The + * elements are copied from the argument to the internal buffer. + */ + @SafeVarargs + public static ObjectIdentityHashSet from(KType... elements) { + final ObjectIdentityHashSet set = new ObjectIdentityHashSet(elements.length); + set.addAll(elements); + return set; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectIndexedContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectIndexedContainer.java new file mode 100755 index 00000000..37ce1fc4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectIndexedContainer.java @@ -0,0 +1,93 @@ +package com.carrotsearch.hppc; + +import java.util.RandomAccess; +import java.util.stream.Stream; + +/** + * An indexed container provides random access to elements based on an index. Indexes + * are zero-based. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeIndexedContainer.java") +public interface ObjectIndexedContainer extends ObjectCollection, RandomAccess { + /** + * Removes the first element that equals e1, returning whether an element has been + * removed. + */ + public boolean removeElement(KType e1); + + /** + * Removes the first element that equals e1, returning its deleted position or + * -1 if the element was not found. + */ + public int removeFirst(KType e1); + + /** + * Removes the last element that equals e1, returning its deleted position or + * -1 if the element was not found. + */ + public int removeLast(KType e1); + + /** + * Returns the index of the first occurrence of the specified element in this list, or -1 if this + * list does not contain the element. + */ + public int indexOf(KType e1); + + /** + * Returns the index of the last occurrence of the specified element in this list, or -1 if this + * list does not contain the element. + */ + public int lastIndexOf(KType e1); + + /** Adds an element to the end of this container (the last index is incremented by one). */ + public void add(KType e1); + + /** + * Inserts the specified element at the specified position in this list. + * + * @param index The index at which the element should be inserted, shifting any existing and + * subsequent elements to the right. + */ + public void insert(int index, KType e1); + + /** + * Replaces the element at the specified position in this list with the specified element. + * + * @return Returns the previous value in the list. + */ + public KType set(int index, KType e1); + + /** + * @return Returns the element at index index from the list. + */ + public KType get(int index); + + /** + * Removes the element at the specified position in this container and returns it. + * + * @see #removeFirst + * @see #removeLast + * @see #removeAll + */ + public KType removeAt(int index); + + /** Removes and returns the last element of this container. This container must not be empty. */ + public KType removeLast(); + + /** + * Removes from this container all of the elements with indexes between fromIndex, + * inclusive, and toIndex, exclusive. + */ + public void removeRange(int fromIndex, int toIndex); + + /** Returns this container elements as a stream. */ + public Stream stream(); + + /** Sorts the elements in this container and returns this container. */ + public ObjectIndexedContainer sort(); + + /** Reverses the elements in this container and returns this container. */ + public ObjectIndexedContainer reverse(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectIntAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectIntAssociativeContainer.java new file mode 100755 index 00000000..13f68440 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectIntAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see ObjectContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface ObjectIntAssociativeContainer extends Iterable> { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator> iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(KType key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectIntPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ObjectIntProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public > T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ObjectIntPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public > T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public ObjectCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public IntContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectIntHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectIntHashMap.java new file mode 100755 index 00000000..47e49998 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectIntHashMap.java @@ -0,0 +1,1089 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of Object to int, implemented using open addressing with + * linear probing for collision resolution. Supports null key. + * + * @see HPPC interfaces diagram + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class ObjectIntHashMap + implements ObjectIntMap, Preallocable, Cloneable, Accountable { + /** The array holding keys. */ + public Object[] keys; + + /** The array holding values. */ + public int[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public ObjectIntHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectIntHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ObjectIntHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ObjectIntHashMap(ObjectIntAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public int put(KType key, int value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == null)) { + int previousValue = hasEmptyKey ? values[mask + 1] : 0; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + final int previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(ObjectIntAssociativeContainer container) { + final int count = size(); + for (ObjectIntCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable> iterable) { + final int count = size(); + for (ObjectIntCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public int putOrAdd(KType key, int putValue, int incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((int) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public int addTo(KType key, int incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public int remove(KType key) { + final int mask = this.mask; + if (((key) == null)) { + if (!hasEmptyKey) { + return 0; + } + hasEmptyKey = false; + int previousValue = values[mask + 1]; + values[mask + 1] = 0; + return previousValue; + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + final int previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof ObjectLookupContainer) { + if (hasEmptyKey && other.contains(null)) { + hasEmptyKey = false; + values[mask + 1] = 0; + } + + final KType[] keys = (KType[]) this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + KType existing; + if (!((existing = keys[slot]) == null) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (ObjectCursor c : other) { + remove((KType) c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectIntPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(null, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0; + } + } + + final KType[] keys = (KType[]) this.keys; + final int[] values = this.values; + for (int slot = 0; slot <= mask; ) { + KType existing; + if (!((existing = keys[slot]) == null) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(null)) { + hasEmptyKey = false; + values[mask + 1] = 0; + } + } + + final KType[] keys = (KType[]) this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + KType existing; + if (!((existing = keys[slot]) == null) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int get(KType key) { + if (((key) == null)) { + return hasEmptyKey ? values[mask + 1] : 0; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0; + } + } + + /** {@inheritDoc} */ + @Override + public int getOrDefault(KType key, int defaultValue) { + if (((key) == null)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(KType key) { + if (((key) == null)) { + return hasEmptyKey; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(KType key) { + final int mask = this.mask; + if (((key) == null)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public int indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public int indexReplace(int index, int newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + int previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, KType key, int value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == null)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == null); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public int indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + int previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, null); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (ObjectIntCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** + * Return true if all keys of some other container exist in this container. Equality comparison is + * performed with this object's {@link #equals(Object, Object)} method. + */ + protected boolean equalElements(ObjectIntHashMap other) { + if (other.size() != size()) { + return false; + } + + for (ObjectIntCursor c : other) { + KType key = (KType) c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final KType[] prevKeys = (KType[]) this.keys; + final int[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final ObjectIntCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new ObjectIntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectIntCursor fetch() { + final int mask = ObjectIntHashMap.this.mask; + while (index <= mask) { + KType existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = (KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = null; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator> iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T procedure) { + final KType[] keys = (KType[]) this.keys; + final int[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(null, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == null)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T predicate) { + final KType[] keys = (KType[]) this.keys; + final int[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(null, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == null)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractObjectCollection + implements ObjectLookupContainer { + private final ObjectIntHashMap owner = ObjectIntHashMap.this; + + @Override + public boolean contains(KType e) { + return owner.containsKey(e); + } + + @Override + public > T forEach(final T procedure) { + owner.forEach((ObjectIntProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public > T forEach(final T predicate) { + owner.forEach((ObjectIntPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator> iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final KType e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator> { + private final ObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new ObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectCursor fetch() { + final int mask = ObjectIntHashMap.this.mask; + while (index <= mask) { + KType existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = (KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = null; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public IntCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractIntCollection { + private final ObjectIntHashMap owner = ObjectIntHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(int value) { + for (ObjectIntCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (ObjectIntCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (ObjectIntCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final int e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final IntPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final IntCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new IntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntCursor fetch() { + final int mask = ObjectIntHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!(((KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public ObjectIntHashMap clone() { + try { + + ObjectIntHashMap cloned = (ObjectIntHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (ObjectIntCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return ObjectBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ObjectIntHashMap from(KType[] keys, int[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ObjectIntHashMap map = new ObjectIntHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(KType key) { + assert !((key) == null); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(KType[] fromKeys, int[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final KType[] keys = (KType[]) this.keys; + final int[] values = this.values; + final int mask = this.mask; + KType existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == null)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == null)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + KType[] prevKeys = (KType[]) this.keys; + int[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = ((KType[]) new Object[arraySize + emptyElementSlot]); + this.values = (new int[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, KType pendingKey, int pendingValue) { + assert assigned == resizeAt && (((KType) keys[slot]) == null) && !((pendingKey) == null); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final KType[] prevKeys = (KType[]) this.keys; + final int[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final KType[] keys = (KType[]) this.keys; + final int[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final KType existing = keys[slot]; + if (((existing) == null)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = null; + values[gapSlot] = 0; + assigned--; + } + + protected boolean equals(Object v1, Object v2) { + return (v1 == v2) || (v1 != null && v1.equals(v2)); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectIntIdentityHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectIntIdentityHashMap.java new file mode 100755 index 00000000..b471a1a7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectIntIdentityHashMap.java @@ -0,0 +1,71 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +/** An identity hash map of Object to int. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeIdentityHashMap.java") +public class ObjectIntIdentityHashMap extends ObjectIntHashMap { + /** New instance with sane defaults. */ + public ObjectIntIdentityHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectIntIdentityHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ObjectIntIdentityHashMap(int expectedElements, double loadFactor) { + super(expectedElements, loadFactor); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ObjectIntIdentityHashMap(ObjectIntAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + @Override + public int hashKey(KType key) { + assert !((key) == null); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(System.identityHashCode(key)); + } + + @Override + public boolean equals(Object v1, Object v2) { + return v1 == v2; + } + + @SuppressWarnings("unchecked") + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ObjectIntIdentityHashMap from(KType[] keys, int[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ObjectIntIdentityHashMap map = new ObjectIntIdentityHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectIntMap.java b/src/main/java/com/carrotsearch/hppc/ObjectIntMap.java new file mode 100755 index 00000000..5f87f0f6 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectIntMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ObjectIntCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface ObjectIntMap extends ObjectIntAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public int get(KType key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public int getOrDefault(KType key, int defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public int put(KType key, int value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(KType key, int value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(ObjectIntAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable> iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public int putOrAdd(KType key, int putValue, int incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public int addTo(KType key, int additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public int remove(KType key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link ObjectIntMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(KType key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public int indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public int indexReplace(int index, int newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, KType key, int value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public int indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectLongAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectLongAssociativeContainer.java new file mode 100755 index 00000000..3d78e376 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectLongAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see ObjectContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface ObjectLongAssociativeContainer extends Iterable> { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator> iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(KType key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectLongPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ObjectLongProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public > T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ObjectLongPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public > T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public ObjectCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public LongContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectLongHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectLongHashMap.java new file mode 100755 index 00000000..1688a68d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectLongHashMap.java @@ -0,0 +1,1089 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of Object to long, implemented using open addressing with + * linear probing for collision resolution. Supports null key. + * + * @see HPPC interfaces diagram + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class ObjectLongHashMap + implements ObjectLongMap, Preallocable, Cloneable, Accountable { + /** The array holding keys. */ + public Object[] keys; + + /** The array holding values. */ + public long[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public ObjectLongHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectLongHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ObjectLongHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ObjectLongHashMap(ObjectLongAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public long put(KType key, long value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == null)) { + long previousValue = hasEmptyKey ? values[mask + 1] : 0L; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + final long previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0L; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(ObjectLongAssociativeContainer container) { + final int count = size(); + for (ObjectLongCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable> iterable) { + final int count = size(); + for (ObjectLongCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public long putOrAdd(KType key, long putValue, long incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((long) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public long addTo(KType key, long incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public long remove(KType key) { + final int mask = this.mask; + if (((key) == null)) { + if (!hasEmptyKey) { + return 0L; + } + hasEmptyKey = false; + long previousValue = values[mask + 1]; + values[mask + 1] = 0L; + return previousValue; + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + final long previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0L; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof ObjectLookupContainer) { + if (hasEmptyKey && other.contains(null)) { + hasEmptyKey = false; + values[mask + 1] = 0L; + } + + final KType[] keys = (KType[]) this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + KType existing; + if (!((existing = keys[slot]) == null) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (ObjectCursor c : other) { + remove((KType) c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectLongPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(null, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0L; + } + } + + final KType[] keys = (KType[]) this.keys; + final long[] values = this.values; + for (int slot = 0; slot <= mask; ) { + KType existing; + if (!((existing = keys[slot]) == null) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(null)) { + hasEmptyKey = false; + values[mask + 1] = 0L; + } + } + + final KType[] keys = (KType[]) this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + KType existing; + if (!((existing = keys[slot]) == null) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public long get(KType key) { + if (((key) == null)) { + return hasEmptyKey ? values[mask + 1] : 0L; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0L; + } + } + + /** {@inheritDoc} */ + @Override + public long getOrDefault(KType key, long defaultValue) { + if (((key) == null)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(KType key) { + if (((key) == null)) { + return hasEmptyKey; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(KType key) { + final int mask = this.mask; + if (((key) == null)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public long indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public long indexReplace(int index, long newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + long previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, KType key, long value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == null)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == null); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public long indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + long previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0L; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, null); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (ObjectLongCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** + * Return true if all keys of some other container exist in this container. Equality comparison is + * performed with this object's {@link #equals(Object, Object)} method. + */ + protected boolean equalElements(ObjectLongHashMap other) { + if (other.size() != size()) { + return false; + } + + for (ObjectLongCursor c : other) { + KType key = (KType) c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final KType[] prevKeys = (KType[]) this.keys; + final long[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final ObjectLongCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new ObjectLongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectLongCursor fetch() { + final int mask = ObjectLongHashMap.this.mask; + while (index <= mask) { + KType existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = (KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = null; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator> iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T procedure) { + final KType[] keys = (KType[]) this.keys; + final long[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(null, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == null)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T predicate) { + final KType[] keys = (KType[]) this.keys; + final long[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(null, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == null)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractObjectCollection + implements ObjectLookupContainer { + private final ObjectLongHashMap owner = ObjectLongHashMap.this; + + @Override + public boolean contains(KType e) { + return owner.containsKey(e); + } + + @Override + public > T forEach(final T procedure) { + owner.forEach((ObjectLongProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public > T forEach(final T predicate) { + owner.forEach((ObjectLongPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator> iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final KType e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator> { + private final ObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new ObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectCursor fetch() { + final int mask = ObjectLongHashMap.this.mask; + while (index <= mask) { + KType existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = (KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = null; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public LongCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractLongCollection { + private final ObjectLongHashMap owner = ObjectLongHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(long value) { + for (ObjectLongCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (ObjectLongCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (ObjectLongCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final long e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final LongPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final LongCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new LongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongCursor fetch() { + final int mask = ObjectLongHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!(((KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public ObjectLongHashMap clone() { + try { + + ObjectLongHashMap cloned = (ObjectLongHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (ObjectLongCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return ObjectBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ObjectLongHashMap from(KType[] keys, long[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ObjectLongHashMap map = new ObjectLongHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(KType key) { + assert !((key) == null); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(KType[] fromKeys, long[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final KType[] keys = (KType[]) this.keys; + final long[] values = this.values; + final int mask = this.mask; + KType existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == null)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == null)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + KType[] prevKeys = (KType[]) this.keys; + long[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = ((KType[]) new Object[arraySize + emptyElementSlot]); + this.values = (new long[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, KType pendingKey, long pendingValue) { + assert assigned == resizeAt && (((KType) keys[slot]) == null) && !((pendingKey) == null); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final KType[] prevKeys = (KType[]) this.keys; + final long[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final KType[] keys = (KType[]) this.keys; + final long[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final KType existing = keys[slot]; + if (((existing) == null)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = null; + values[gapSlot] = 0L; + assigned--; + } + + protected boolean equals(Object v1, Object v2) { + return (v1 == v2) || (v1 != null && v1.equals(v2)); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectLongIdentityHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectLongIdentityHashMap.java new file mode 100755 index 00000000..886d6742 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectLongIdentityHashMap.java @@ -0,0 +1,71 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +/** An identity hash map of Object to long. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeIdentityHashMap.java") +public class ObjectLongIdentityHashMap extends ObjectLongHashMap { + /** New instance with sane defaults. */ + public ObjectLongIdentityHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectLongIdentityHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ObjectLongIdentityHashMap(int expectedElements, double loadFactor) { + super(expectedElements, loadFactor); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ObjectLongIdentityHashMap(ObjectLongAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + @Override + public int hashKey(KType key) { + assert !((key) == null); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(System.identityHashCode(key)); + } + + @Override + public boolean equals(Object v1, Object v2) { + return v1 == v2; + } + + @SuppressWarnings("unchecked") + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ObjectLongIdentityHashMap from(KType[] keys, long[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ObjectLongIdentityHashMap map = new ObjectLongIdentityHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectLongMap.java b/src/main/java/com/carrotsearch/hppc/ObjectLongMap.java new file mode 100755 index 00000000..4cab9639 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectLongMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ObjectLongCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface ObjectLongMap extends ObjectLongAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public long get(KType key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public long getOrDefault(KType key, long defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public long put(KType key, long value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(KType key, long value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(ObjectLongAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable> iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public long putOrAdd(KType key, long putValue, long incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public long addTo(KType key, long additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public long remove(KType key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link ObjectLongMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(KType key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public long indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public long indexReplace(int index, long newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, KType key, long value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public long indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectLookupContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectLookupContainer.java new file mode 100755 index 00000000..ee0982c0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectLookupContainer.java @@ -0,0 +1,12 @@ +package com.carrotsearch.hppc; + +/** + * Marker interface for containers that can check if they contain a given object in at least time + * O(log n) and ideally in amortized constant time O(1). + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeLookupContainer.java") +public interface ObjectLookupContainer extends ObjectContainer { + public boolean contains(KType e); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectObjectAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectObjectAssociativeContainer.java new file mode 100755 index 00000000..551388ef --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectObjectAssociativeContainer.java @@ -0,0 +1,106 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see ObjectContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface ObjectObjectAssociativeContainer + extends Iterable> { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator> iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(KType key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectObjectPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ObjectObjectProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public > T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ObjectObjectPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public > T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public ObjectCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public ObjectContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectObjectHashMap.java new file mode 100755 index 00000000..855027cd --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectObjectHashMap.java @@ -0,0 +1,1059 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of Object to Object, implemented using open addressing with + * linear probing for collision resolution. Supports null key. Supports null values. + * + * @see HPPC interfaces diagram + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class ObjectObjectHashMap + implements ObjectObjectMap, Preallocable, Cloneable, Accountable { + /** The array holding keys. */ + public Object[] keys; + + /** The array holding values. */ + public Object[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public ObjectObjectHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectObjectHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ObjectObjectHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ObjectObjectHashMap( + ObjectObjectAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public VType put(KType key, VType value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == null)) { + VType previousValue = hasEmptyKey ? (VType) values[mask + 1] : null; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + final VType previousValue = (VType) values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return null; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(ObjectObjectAssociativeContainer container) { + final int count = size(); + for (ObjectObjectCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll( + Iterable> iterable) { + final int count = size(); + for (ObjectObjectCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** {@inheritDoc} */ + @Override + public VType remove(KType key) { + final int mask = this.mask; + if (((key) == null)) { + if (!hasEmptyKey) { + return null; + } + hasEmptyKey = false; + VType previousValue = (VType) values[mask + 1]; + values[mask + 1] = null; + return previousValue; + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + final VType previousValue = (VType) values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return null; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof ObjectLookupContainer) { + if (hasEmptyKey && other.contains(null)) { + hasEmptyKey = false; + values[mask + 1] = null; + } + + final KType[] keys = (KType[]) this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + KType existing; + if (!((existing = keys[slot]) == null) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (ObjectCursor c : other) { + remove((KType) c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectObjectPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(null, (VType) values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = null; + } + } + + final KType[] keys = (KType[]) this.keys; + final VType[] values = (VType[]) this.values; + for (int slot = 0; slot <= mask; ) { + KType existing; + if (!((existing = keys[slot]) == null) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(null)) { + hasEmptyKey = false; + values[mask + 1] = null; + } + } + + final KType[] keys = (KType[]) this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + KType existing; + if (!((existing = keys[slot]) == null) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public VType get(KType key) { + if (((key) == null)) { + return hasEmptyKey ? (VType) values[mask + 1] : null; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return (VType) values[slot]; + } + slot = (slot + 1) & mask; + } + + return null; + } + } + + /** {@inheritDoc} */ + @Override + public VType getOrDefault(KType key, VType defaultValue) { + if (((key) == null)) { + return hasEmptyKey ? (VType) values[mask + 1] : defaultValue; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return (VType) values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(KType key) { + if (((key) == null)) { + return hasEmptyKey; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(KType key) { + final int mask = this.mask; + if (((key) == null)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public VType indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return (VType) values[index]; + } + + /** {@inheritDoc} */ + @Override + public VType indexReplace(int index, VType newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + VType previousValue = (VType) values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, KType key, VType value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == null)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == null); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public VType indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + VType previousValue = (VType) values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = null; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, null); + + Arrays.fill(values, null); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (ObjectObjectCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** + * Return true if all keys of some other container exist in this container. Equality comparison is + * performed with this object's {@link #equals(Object, Object)} method. Values are compared using + * {@link Objects#equals(Object)} method. + */ + protected boolean equalElements(ObjectObjectHashMap other) { + if (other.size() != size()) { + return false; + } + + for (ObjectObjectCursor c : other) { + KType key = (KType) c.key; + if (!containsKey(key) || !java.util.Objects.equals(c.value, get(key))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final KType[] prevKeys = (KType[]) this.keys; + final VType[] prevValues = (VType[]) this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final ObjectObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new ObjectObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectObjectCursor fetch() { + final int mask = ObjectObjectHashMap.this.mask; + while (index <= mask) { + KType existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = (KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = (VType) values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = null; + cursor.value = (VType) values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator> iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T procedure) { + final KType[] keys = (KType[]) this.keys; + final VType[] values = (VType[]) this.values; + + if (hasEmptyKey) { + procedure.apply(null, (VType) values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == null)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T predicate) { + final KType[] keys = (KType[]) this.keys; + final VType[] values = (VType[]) this.values; + + if (hasEmptyKey) { + if (!predicate.apply(null, (VType) values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == null)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractObjectCollection + implements ObjectLookupContainer { + private final ObjectObjectHashMap owner = ObjectObjectHashMap.this; + + @Override + public boolean contains(KType e) { + return owner.containsKey(e); + } + + @Override + public > T forEach(final T procedure) { + owner.forEach((ObjectObjectProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public > T forEach(final T predicate) { + owner.forEach((ObjectObjectPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator> iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final KType e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator> { + private final ObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new ObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectCursor fetch() { + final int mask = ObjectObjectHashMap.this.mask; + while (index <= mask) { + KType existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = (KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = null; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public ObjectCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractObjectCollection { + private final ObjectObjectHashMap owner = ObjectObjectHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(VType value) { + for (ObjectObjectCursor c : owner) { + if (java.util.Objects.equals(value, c.value)) { + return true; + } + } + return false; + } + + @Override + public > T forEach(T procedure) { + for (ObjectObjectCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public > T forEach(T predicate) { + for (ObjectObjectCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator> iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final VType e) { + return owner.removeAll((key, value) -> java.util.Objects.equals(e, value)); + } + + @Override + public int removeAll(final ObjectPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator> { + private final ObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new ObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectCursor fetch() { + final int mask = ObjectObjectHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!(((KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.value = (VType) values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = (VType) values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public ObjectObjectHashMap clone() { + try { + + ObjectObjectHashMap cloned = (ObjectObjectHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (ObjectObjectCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return ObjectBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ObjectObjectHashMap from( + KType[] keys, VType[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ObjectObjectHashMap map = new ObjectObjectHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(KType key) { + assert !((key) == null); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(KType[] fromKeys, VType[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final KType[] keys = (KType[]) this.keys; + final VType[] values = (VType[]) this.values; + final int mask = this.mask; + KType existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == null)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == null)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + KType[] prevKeys = (KType[]) this.keys; + VType[] prevValues = (VType[]) this.values; + try { + int emptyElementSlot = 1; + this.keys = ((KType[]) new Object[arraySize + emptyElementSlot]); + this.values = ((VType[]) new Object[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, KType pendingKey, VType pendingValue) { + assert assigned == resizeAt && (((KType) keys[slot]) == null) && !((pendingKey) == null); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final KType[] prevKeys = (KType[]) this.keys; + final VType[] prevValues = (VType[]) this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final KType[] keys = (KType[]) this.keys; + final VType[] values = (VType[]) this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final KType existing = keys[slot]; + if (((existing) == null)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = null; + values[gapSlot] = null; + assigned--; + } + + protected boolean equals(Object v1, Object v2) { + return (v1 == v2) || (v1 != null && v1.equals(v2)); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectObjectIdentityHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectObjectIdentityHashMap.java new file mode 100755 index 00000000..c726faa1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectObjectIdentityHashMap.java @@ -0,0 +1,91 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; + +/** An identity hash map of Object to Object. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeIdentityHashMap.java") +public class ObjectObjectIdentityHashMap extends ObjectObjectHashMap { + /** New instance with sane defaults. */ + public ObjectObjectIdentityHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectObjectIdentityHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ObjectObjectIdentityHashMap(int expectedElements, double loadFactor) { + super(expectedElements, loadFactor); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ObjectObjectIdentityHashMap( + ObjectObjectAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + @Override + public int hashKey(KType key) { + assert !((key) == null); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(System.identityHashCode(key)); + } + + @Override + public boolean equals(Object v1, Object v2) { + return v1 == v2; + } + + @SuppressWarnings("unchecked") + @Override + protected boolean equalElements(ObjectObjectHashMap other) { + if (other.size() != size()) { + return false; + } + + for (ObjectObjectCursor c : other) { + KType key = (KType) c.key; + if (!containsKey(key) + || !equals(c.value, get(key))) { // Compare values using the same function as keys. + return false; + } + } + + return true; + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ObjectObjectIdentityHashMap from( + KType[] keys, VType[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ObjectObjectIdentityHashMap map = new ObjectObjectIdentityHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectObjectMap.java b/src/main/java/com/carrotsearch/hppc/ObjectObjectMap.java new file mode 100755 index 00000000..c1316b06 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectObjectMap.java @@ -0,0 +1,183 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ObjectObjectCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface ObjectObjectMap + extends ObjectObjectAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public VType get(KType key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public VType getOrDefault(KType key, VType defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public VType put(KType key, VType value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(KType key, VType value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(ObjectObjectAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll( + Iterable> iterable); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public VType remove(KType key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link ObjectObjectMap} and both objects contains exactly the + * same key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(KType key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public VType indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public VType indexReplace(int index, VType newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, KType key, VType value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public VType indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectSet.java b/src/main/java/com/carrotsearch/hppc/ObjectSet.java new file mode 100755 index 00000000..24355d4d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectSet.java @@ -0,0 +1,33 @@ +package com.carrotsearch.hppc; + +/** A set of Objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeSet.java") +public interface ObjectSet extends ObjectCollection { + /** + * Adds k to the set. + * + * @return Returns true if this element was not part of the set before. Returns + * false if an equal element is already part of the set, does not replace the + * existing element with the argument. + */ + public boolean add(KType k); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); + + /** + * Adds all elements from the given {@link ObjectContainer} to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + * @since 0.9.1 + */ + public int addAll(ObjectContainer container); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectShortAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectShortAssociativeContainer.java new file mode 100755 index 00000000..a5c46c27 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectShortAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see ObjectContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface ObjectShortAssociativeContainer extends Iterable> { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator> iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(KType key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ObjectShortPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ObjectShortProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public > T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ObjectShortPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public > T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public ObjectCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public ShortContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectShortHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectShortHashMap.java new file mode 100755 index 00000000..9d492a11 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectShortHashMap.java @@ -0,0 +1,1089 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of Object to short, implemented using open addressing with + * linear probing for collision resolution. Supports null key. + * + * @see HPPC interfaces diagram + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class ObjectShortHashMap + implements ObjectShortMap, Preallocable, Cloneable, Accountable { + /** The array holding keys. */ + public Object[] keys; + + /** The array holding values. */ + public short[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public ObjectShortHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectShortHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ObjectShortHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ObjectShortHashMap(ObjectShortAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public short put(KType key, short value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == null)) { + short previousValue = hasEmptyKey ? values[mask + 1] : ((short) 0); + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + final short previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return ((short) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(ObjectShortAssociativeContainer container) { + final int count = size(); + for (ObjectShortCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable> iterable) { + final int count = size(); + for (ObjectShortCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public short putOrAdd(KType key, short putValue, short incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((short) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public short addTo(KType key, short incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public short remove(KType key) { + final int mask = this.mask; + if (((key) == null)) { + if (!hasEmptyKey) { + return ((short) 0); + } + hasEmptyKey = false; + short previousValue = values[mask + 1]; + values[mask + 1] = ((short) 0); + return previousValue; + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + final short previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return ((short) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof ObjectLookupContainer) { + if (hasEmptyKey && other.contains(null)) { + hasEmptyKey = false; + values[mask + 1] = ((short) 0); + } + + final KType[] keys = (KType[]) this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + KType existing; + if (!((existing = keys[slot]) == null) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (ObjectCursor c : other) { + remove((KType) c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectShortPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(null, values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = ((short) 0); + } + } + + final KType[] keys = (KType[]) this.keys; + final short[] values = this.values; + for (int slot = 0; slot <= mask; ) { + KType existing; + if (!((existing = keys[slot]) == null) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ObjectPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(null)) { + hasEmptyKey = false; + values[mask + 1] = ((short) 0); + } + } + + final KType[] keys = (KType[]) this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + KType existing; + if (!((existing = keys[slot]) == null) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public short get(KType key) { + if (((key) == null)) { + return hasEmptyKey ? values[mask + 1] : ((short) 0); + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return ((short) 0); + } + } + + /** {@inheritDoc} */ + @Override + public short getOrDefault(KType key, short defaultValue) { + if (((key) == null)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(KType key) { + if (((key) == null)) { + return hasEmptyKey; + } else { + final KType[] keys = (KType[]) this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(KType key) { + final int mask = this.mask; + if (((key) == null)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final KType[] keys = (KType[]) this.keys; + int slot = hashKey(key) & mask; + + KType existing; + while (!((existing = keys[slot]) == null)) { + if (this.equals(key, existing)) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public short indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public short indexReplace(int index, short newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + short previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, KType key, short value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == null)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == null); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public short indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + short previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = ((short) 0); + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, null); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (ObjectShortCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** + * Return true if all keys of some other container exist in this container. Equality comparison is + * performed with this object's {@link #equals(Object, Object)} method. + */ + protected boolean equalElements(ObjectShortHashMap other) { + if (other.size() != size()) { + return false; + } + + for (ObjectShortCursor c : other) { + KType key = (KType) c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final KType[] prevKeys = (KType[]) this.keys; + final short[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final ObjectShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new ObjectShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectShortCursor fetch() { + final int mask = ObjectShortHashMap.this.mask; + while (index <= mask) { + KType existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = (KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = null; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator> iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T procedure) { + final KType[] keys = (KType[]) this.keys; + final short[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(null, values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == null)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T predicate) { + final KType[] keys = (KType[]) this.keys; + final short[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(null, values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == null)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractObjectCollection + implements ObjectLookupContainer { + private final ObjectShortHashMap owner = ObjectShortHashMap.this; + + @Override + public boolean contains(KType e) { + return owner.containsKey(e); + } + + @Override + public > T forEach(final T procedure) { + owner.forEach((ObjectShortProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public > T forEach(final T predicate) { + owner.forEach((ObjectShortPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator> iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final KType e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator> { + private final ObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new ObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectCursor fetch() { + final int mask = ObjectShortHashMap.this.mask; + while (index <= mask) { + KType existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = (KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = null; + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public ShortCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractShortCollection { + private final ObjectShortHashMap owner = ObjectShortHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(short value) { + for (ObjectShortCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (ObjectShortCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (ObjectShortCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final short e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final ShortPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new ShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortCursor fetch() { + final int mask = ObjectShortHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!(((KType) keys[slot]) == null)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public ObjectShortHashMap clone() { + try { + + ObjectShortHashMap cloned = (ObjectShortHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (ObjectShortCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return ObjectBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ObjectShortHashMap from(KType[] keys, short[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ObjectShortHashMap map = new ObjectShortHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(KType key) { + assert !((key) == null); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(KType[] fromKeys, short[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final KType[] keys = (KType[]) this.keys; + final short[] values = this.values; + final int mask = this.mask; + KType existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == null)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == null)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + KType[] prevKeys = (KType[]) this.keys; + short[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = ((KType[]) new Object[arraySize + emptyElementSlot]); + this.values = (new short[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, KType pendingKey, short pendingValue) { + assert assigned == resizeAt && (((KType) keys[slot]) == null) && !((pendingKey) == null); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final KType[] prevKeys = (KType[]) this.keys; + final short[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final KType[] keys = (KType[]) this.keys; + final short[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final KType existing = keys[slot]; + if (((existing) == null)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = null; + values[gapSlot] = ((short) 0); + assigned--; + } + + protected boolean equals(Object v1, Object v2) { + return (v1 == v2) || (v1 != null && v1.equals(v2)); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectShortIdentityHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectShortIdentityHashMap.java new file mode 100755 index 00000000..c5c04c28 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectShortIdentityHashMap.java @@ -0,0 +1,71 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +/** An identity hash map of Object to short. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeIdentityHashMap.java") +public class ObjectShortIdentityHashMap extends ObjectShortHashMap { + /** New instance with sane defaults. */ + public ObjectShortIdentityHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectShortIdentityHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ObjectShortIdentityHashMap(int expectedElements, double loadFactor) { + super(expectedElements, loadFactor); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ObjectShortIdentityHashMap(ObjectShortAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + @Override + public int hashKey(KType key) { + assert !((key) == null); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(System.identityHashCode(key)); + } + + @Override + public boolean equals(Object v1, Object v2) { + return v1 == v2; + } + + @SuppressWarnings("unchecked") + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ObjectShortIdentityHashMap from(KType[] keys, short[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ObjectShortIdentityHashMap map = new ObjectShortIdentityHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectShortMap.java b/src/main/java/com/carrotsearch/hppc/ObjectShortMap.java new file mode 100755 index 00000000..df88b9e2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectShortMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ObjectShortCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface ObjectShortMap extends ObjectShortAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public short get(KType key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public short getOrDefault(KType key, short defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public short put(KType key, short value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(KType key, short value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(ObjectShortAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable> iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public short putOrAdd(KType key, short putValue, short incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public short addTo(KType key, short additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public short remove(KType key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link ObjectShortMap} and both objects contains exactly the + * same key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(KType key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public short indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public short indexReplace(int index, short newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, KType key, short value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public short indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/ObjectStack.java b/src/main/java/com/carrotsearch/hppc/ObjectStack.java new file mode 100755 index 00000000..d768be98 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectStack.java @@ -0,0 +1,145 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ObjectCursor; +import java.util.Arrays; + +/** + * A subclass of {@link ObjectArrayList} adding stack-related utility methods. The top of the stack + * is at the {@link #size()} - 1 element. + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java") +public class ObjectStack extends ObjectArrayList { + /** New instance with sane defaults. */ + public ObjectStack() { + super(); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ObjectStack(int expectedElements) { + super(expectedElements); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public ObjectStack(int expectedElements, ArraySizingStrategy resizer) { + super(expectedElements, resizer); + } + + /** Create a stack by pushing all elements of another container to it. */ + public ObjectStack(ObjectContainer container) { + super(container); + } + + /** Adds one Object to the stack. */ + public void push(KType e1) { + ensureBufferSpace(1); + buffer[elementsCount++] = e1; + } + + /** Adds two Objects to the stack. */ + public void push(KType e1, KType e2) { + ensureBufferSpace(2); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + } + + /** Adds three Objects to the stack. */ + public void push(KType e1, KType e2, KType e3) { + ensureBufferSpace(3); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + buffer[elementsCount++] = e3; + } + + /** Adds four Objects to the stack. */ + public void push(KType e1, KType e2, KType e3, KType e4) { + ensureBufferSpace(4); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + buffer[elementsCount++] = e3; + buffer[elementsCount++] = e4; + } + + /** Add a range of array elements to the stack. */ + public void push(KType[] elements, int start, int len) { + assert start >= 0 && len >= 0; + + ensureBufferSpace(len); + System.arraycopy(elements, start, buffer, elementsCount, len); + elementsCount += len; + } + + /** + * Vararg-signature method for pushing elements at the top of the stack. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + */ + @SafeVarargs + public final void push(KType... elements) { + push(elements, 0, elements.length); + } + + /** Pushes all elements from another container to the top of the stack. */ + public int pushAll(ObjectContainer container) { + return addAll(container); + } + + /** Pushes all elements from another iterable to the top of the stack. */ + public int pushAll(Iterable> iterable) { + return addAll(iterable); + } + + /** Discard an arbitrary number of elements from the top of the stack. */ + public void discard(int count) { + assert elementsCount >= count; + + elementsCount -= count; + + Arrays.fill(buffer, elementsCount, elementsCount + count, null); + } + + /** Discard the top element from the stack. */ + public void discard() { + assert elementsCount > 0; + + elementsCount--; + + buffer[elementsCount] = null; + } + + /** Remove the top element from the stack and return it. */ + public KType pop() { + return removeLast(); + } + + /** Peek at the top element on the stack. */ + public KType peek() { + assert elementsCount > 0; + return (KType) buffer[elementsCount - 1]; + } + + /** Create a stack by pushing a variable number of arguments to it. */ + @SafeVarargs + public static ObjectStack from(KType... elements) { + final ObjectStack stack = new ObjectStack(elements.length); + stack.push(elements); + return stack; + } + + /** {@inheritDoc} */ + @Override + public ObjectStack clone() { + return (ObjectStack) super.clone(); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/PgmIndexUtil.java b/src/main/java/com/carrotsearch/hppc/PgmIndexUtil.java new file mode 100755 index 00000000..9793ab2b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/PgmIndexUtil.java @@ -0,0 +1,122 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc; + +/** Utility methods for {@code KTypePgmIndex}. */ +final class PgmIndexUtil { + + /** Adds the first key of the current segment to the segment data bytes. */ + static void addKey(KType key, IntArrayList segmentData) { + throw new UnsupportedOperationException("Invalid for generic type: " + key); + } + + /** Adds the first key of the current segment to the segment data bytes. */ + static void addKey(int key, IntArrayList segmentData) { + segmentData.add(key); + } + + /** Adds the first key of the current segment to the segment data bytes. */ + static void addKey(float key, IntArrayList segmentData) { + addKey(Float.floatToIntBits(key), segmentData); + } + + /** Adds the first key of the current segment to the segment data bytes. */ + static void addKey(long key, IntArrayList segmentData) { + segmentData.add((int) key); + segmentData.add((int) (key >> 32)); + } + + /** Adds the first key of the current segment to the segment data bytes. */ + static void addKey(double key, IntArrayList segmentData) { + addKey(Double.doubleToRawLongBits(key), segmentData); + } + + /** Gets the first key of the segment at the given data index. */ + static KType getKey(int segmentDataIndex, int[] segmentData, KType keyType) { + throw new UnsupportedOperationException("Invalid for generic type: " + keyType); + } + + /** Gets the first key of the segment at the given data index. */ + static int getKey(int segmentDataIndex, int[] segmentData, int keyType) { + return segmentData[segmentDataIndex]; + } + + /** Gets the first key of the segment at the given data index. */ + static float getKey(int segmentDataIndex, int[] segmentData, float keyType) { + return Float.intBitsToFloat(getKey(segmentDataIndex, segmentData, 0)); + } + + /** Gets the first key of the segment at the given data index. */ + static long getKey(int segmentDataIndex, int[] segmentData, long keyType) { + return (segmentData[segmentDataIndex] & 0xFFFFFFFFL) + | (((long) segmentData[segmentDataIndex + 1]) << 32); + } + + /** Gets the first key of the segment at the given data index. */ + static double getKey(int segmentDataIndex, int[] segmentData, double keyType) { + return Double.longBitsToDouble(getKey(segmentDataIndex, segmentData, 0L)); + } + + /** + * Adds the intercept of the current segment to the segment data bytes. The intercept is stored as + * an int for a key size equal to 1, otherwise it is stored as a long. + * + * @param keySize The size of the key, measure in {@link Integer#BYTES}. + */ + static void addIntercept(long intercept, IntArrayList segmentData, int keySize) { + assert keySize >= 1 && keySize <= 2; + if (keySize == 1) { + addKey((int) intercept, segmentData); + } else { + addKey(intercept, segmentData); + } + } + + /** + * Gets the intercept of the segment at the given data index. + * + * @param keySize The size of the key, measure in {@link Integer#BYTES}. + */ + static long getIntercept(int segmentDataIndex, int[] segmentData, int keySize) { + assert keySize >= 1 && keySize <= 2; + if (keySize == 1) { + return getKey(segmentDataIndex, segmentData, 0); + } + return getKey(segmentDataIndex, segmentData, 0L); + } + + /** + * Adds the slope of the current segment to the segment data bytes. The intercept is stored as a + * float for a key size equal to 1, otherwise it is stored as a double. + * + * @param keySize The size of the key, measure in {@link Integer#BYTES}. + */ + static void addSlope(double slope, IntArrayList segmentData, int keySize) { + assert keySize >= 1 && keySize <= 2; + if (keySize == 1) { + addKey((float) slope, segmentData); + } else { + addKey(slope, segmentData); + } + } + + /** + * Gets the slope of the segment at the given data index. + * + * @param keySize The size of the key, measure in {@link Integer#BYTES}. + */ + static double getSlope(int segmentDataIndex, int[] segmentData, int keySize) { + assert keySize >= 1 && keySize <= 2; + if (keySize == 1) { + return getKey(segmentDataIndex, segmentData, 0f); + } + return getKey(segmentDataIndex, segmentData, 0d); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/PlaModel.java b/src/main/java/com/carrotsearch/hppc/PlaModel.java new file mode 100755 index 00000000..49317404 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/PlaModel.java @@ -0,0 +1,414 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc; + +import java.util.Arrays; + +/** + * Optimal Piecewise Linear Approximation Model for KType keys. + * + *

Learns a mapping that returns a position for a KType key which is at most epsilon + * away from the correct one in a sorted list of keys. It is optimal and piecewise because it learns + * the minimum number of epsilon-approximate segments. + * + *

The PLA-model consists of a sequence segments. A segment s is a triple (key,slope,intercept) + * that indexes a range of keys through the function fs(k) = k × slope + intercept, which provides + * an epsilon-approximation of the position of the key k. + */ +public class PlaModel implements Accountable { + + /** Initial capacity of the lower and upper point lists. */ + private static final int INITIAL_CAPACITY = 1 << 8; + + /** Epsilon precision of the PLA-model. */ + private int epsilon; + + /** First key of the current segment. */ + private double firstKey; + + /** Previous key used to check that keys are added in strictly increasing sequence. */ + private double previousKey; + + /** Number of points in the convex hull for the current segment. */ + private int numPointsInHull; + + /** Enclosing rectangle for the current segment. */ + private final Point[] rect = new Point[4]; + + /** + * Ordered list of lower points for the current segment. Inside the list, allocated points are + * re-used. + */ + private final PointList lower = new PointList(INITIAL_CAPACITY); + + /** + * Ordered list of upper points for the current segment. Inside the list, allocated points are + * re-used. + */ + private final PointList upper = new PointList(INITIAL_CAPACITY); + + /** Index of the first lower point to compare to. */ + private int lowerStart; + + /** Index of the first upper point to compare to. */ + private int upperStart; + + // Re-used mutable points and slopes. + private final Point point1 = new Point(); + private final Point point2 = new Point(); + private final Slope slope1 = new Slope(); + private final Slope slope2 = new Slope(); + private final Slope slopeTmp = new Slope(); + private final Slope slopeMin = new Slope(); + private final Slope slopeMax = new Slope(); + + /** + * Creates an optimal PLA-model with the provided epsilon precision. + * + * @param epsilon must be greater than or equal to 0. + */ + public PlaModel(int epsilon) { + setEpsilon(epsilon); + for (int i = 0; i < rect.length; i++) { + rect[i] = new Point(); + } + reset(); + } + + /** Sets epsilon precision which must be greater than or equal to 0. */ + public void setEpsilon(int epsilon) { + if (epsilon < 0) { + throw new IllegalArgumentException("epsilon must be >= 0"); + } + this.epsilon = epsilon; + } + + private void reset() { + previousKey = Double.NEGATIVE_INFINITY; + numPointsInHull = 0; + lower.clear(); + upper.clear(); + } + + /** + * Adds a key to this PLA-model. The keys must be provided in a strictly increasing sequence. That + * is, the key must be greater than the previous key. + * + * @param index The index of the key in the sorted key list. + * @param segmentConsumer The consumer to call when a new segment is built in the PLA-model. + */ + public void addKey(double key, int index, SegmentConsumer segmentConsumer) { + if (key <= previousKey) { + throw new IllegalArgumentException("Keys must be increasing"); + } + previousKey = key; + point1.set(key, addEpsilon(index)); + point2.set(key, subtractEpsilon(index)); + + if (numPointsInHull > 1) { + slope1.set(rect[0], rect[2]); + slope2.set(rect[1], rect[3]); + boolean outside_line1 = slopeTmp.set(rect[2], point1).isLessThan(slope1); + boolean outside_line2 = slopeTmp.set(rect[3], point2).isGreaterThan(slope2); + if (outside_line1 || outside_line2) { + produceSegment(segmentConsumer); + numPointsInHull = 0; + } + } + if (numPointsInHull == 0) { + firstKey = key; + rect[0].set(point1); + rect[1].set(point2); + upper.clear(); + lower.clear(); + upper.add(point1); + lower.add(point2); + upperStart = lowerStart = 0; + numPointsInHull++; + return; + } + if (numPointsInHull == 1) { + rect[2].set(point2); + rect[3].set(point1); + upper.add(point1); + lower.add(point2); + numPointsInHull++; + return; + } + + if (slopeTmp.set(rect[1], point1).isLessThan(slope2)) { + // Find extreme slope. + slopeMin.set(point1, lower.get(lowerStart)); + int min_i = lowerStart; + for (int i = lowerStart + 1; i < lower.size(); i++) { + slopeTmp.set(point1, lower.get(i)); + if (slopeTmp.isGreaterThan(slopeMin)) { + break; + } + slopeMin.set(slopeTmp); + min_i = i; + } + rect[1].set(lower.get(min_i)); + rect[3].set(point1); + lowerStart = min_i; + + // Hull update. + int end = upper.size(); + while (end >= upperStart + 2 && cross(upper.get(end - 2), upper.get(end - 1), point1) <= 0) { + end--; + } + upper.clearFrom(end); + upper.add(point1); + } + + if (slopeTmp.set(rect[0], point2).isGreaterThan(slope1)) { + // Find extreme slope. + slopeMax.set(point2, upper.get(upperStart)); + int max_i = upperStart; + for (int i = upperStart + 1; i < upper.size(); i++) { + slopeTmp.set(point2, upper.get(i)); + if (slopeTmp.isLessThan(slopeMax)) { + break; + } + slopeMax.set(slopeTmp); + max_i = i; + } + rect[0].set(upper.get(max_i)); + rect[2].set(point2); + upperStart = max_i; + + // Hull update. + int end = lower.size(); + while (end >= lowerStart + 2 && cross(lower.get(end - 2), lower.get(end - 1), point2) >= 0) { + end--; + } + lower.clearFrom(end); + lower.add(point2); + } + + numPointsInHull++; + } + + private void produceSegment(SegmentConsumer segmentConsumer) { + double slope; + long intercept; + + if (numPointsInHull == 1) { + slope = 0d; + intercept = ((long) rect[0].y + rect[1].y) >>> 1; + + } else { + Point p0 = rect[0]; + Point p1 = rect[1]; + Point p2 = rect[2]; + Point p3 = rect[3]; + + // Compute the slope intersection point. + double intersectX; + double intersectY; + slope1.set(p0, p2); + slope2.set(p1, p3); + if (slope1.isEqual(slope2)) { + intersectX = p0.x; + intersectY = p0.y; + } else { + slopeTmp.set(p0, p1); + double a = slope1.dx * slope2.dy - slope1.dy * slope2.dx; + double b = (slopeTmp.dx * slope2.dy - slopeTmp.dy * slope2.dx) / a; + intersectX = p0.x + b * slope1.dx; + intersectY = p0.y + b * slope1.dy; + } + + // Compute the slope range. + double minSlope = Slope.asDouble(p0, p2); + double maxSlope = Slope.asDouble(p1, p3); + + // Compute the segment slope and intercept. + slope = (minSlope + maxSlope) / 2d; + intercept = (long) (intersectY - (intersectX - firstKey) * slope); + } + + segmentConsumer.accept(firstKey, slope, intercept); + } + + /** + * Finishes the PLA-model construction. Declares that no additional keys will be added. Builds the + * last segment and calls the provided {@link SegmentConsumer}. + */ + public void finish(SegmentConsumer segmentConsumer) { + produceSegment(segmentConsumer); + reset(); + } + + @Override + public long ramBytesAllocated() { + // int: epsilon, numPointsInHull, lowerStart, upperStart + // double: firstKey, previousKey + // Point: rect[4], point1, point2 + // Slope: slope1, slope2, slopeTmp, slopeMin, slopeMax + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + 2 * Double.BYTES + + 6L * Point.RAM_BYTES_ALLOCATED + + lower.ramBytesAllocated() + + upper.ramBytesAllocated() + + 5L * Slope.RAM_BYTES_ALLOCATED; + } + + @Override + public long ramBytesUsed() { + return ramBytesAllocated(); + } + + private int addEpsilon(int index) { + try { + return Math.addExact(index, epsilon); + } catch (ArithmeticException e) { + return Integer.MAX_VALUE; + } + } + + private int subtractEpsilon(int index) { + try { + return Math.subtractExact(index, epsilon); + } catch (ArithmeticException e) { + return Integer.MIN_VALUE; + } + } + + private static double cross(Point o, Point a, Point b) { + return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x); + } + + /** Consumer notified when a new segment is built by the {@link PlaModel}. */ + public interface SegmentConsumer { + + /** + * Consumes a new segment. The segment is defined by the epsilon-approximation function fs(k) = + * k × slope + intercept. + * + * @param firstKey The first key of the segment. + * @param slope The segment slope. + * @param intercept The segment intercept. + */ + void accept(double firstKey, double slope, long intercept); + } + + /** Re-usable mutable (x,y) point. */ + private static class Point { + + static final int RAM_BYTES_ALLOCATED = + RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + Double.BYTES + Long.BYTES; + + double x; + long y; + + Point set(double x, long y) { + this.x = x; + this.y = y; + return this; + } + + Point set(Point p) { + return set(p.x, p.y); + } + } + + /** List of mutable {@link Point}. Re-uses allocated points instead of creating new instances. */ + private static class PointList implements Accountable { + + Point[] points; + int size; + int numAllocated; + + PointList(int initialCapacity) { + points = new Point[initialCapacity]; + } + + void add(Point point) { + if (size == points.length) { + int newSize = + BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE.grow(points.length, size, 1); + points = Arrays.copyOf(points, newSize); + } + if (size == numAllocated) { + points[numAllocated++] = new Point(); + } + points[size++].set(point); + } + + Point get(int index) { + return points[index]; + } + + int size() { + return size; + } + + void clear() { + size = 0; + } + + void clearFrom(int end) { + size = end; + } + + @Override + public long ramBytesAllocated() { + // int: size, numAllocated + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 2 * Integer.BYTES + + RamUsageEstimator.shallowSizeOfArray(points) + + (long) numAllocated * Point.RAM_BYTES_ALLOCATED; + } + + @Override + public long ramBytesUsed() { + return ramBytesAllocated(); + } + } + + /** Re-usable mutable (dx,dy) slope. */ + private static class Slope { + + static final int RAM_BYTES_ALLOCATED = + RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + Double.BYTES + Long.BYTES; + + double dx; + long dy; + + void set(Slope s) { + dx = s.dx; + dy = s.dy; + } + + Slope set(Point p1, Point p2) { + dx = p2.x - p1.x; + dy = p2.y - p1.y; + return this; + } + + boolean isLessThan(Slope s) { + return dy * s.dx < dx * s.dy; + } + + boolean isGreaterThan(Slope s) { + return dy * s.dx > dx * s.dy; + } + + boolean isEqual(Slope s) { + return Double.doubleToLongBits(dy * s.dx) == Double.doubleToLongBits(dx * s.dy); + } + + static double asDouble(Point p1, Point p2) { + return (double) (p2.y - p1.y) / (p2.x - p1.x); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/Preallocable.java b/src/main/java/com/carrotsearch/hppc/Preallocable.java new file mode 100755 index 00000000..1251bcb9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/Preallocable.java @@ -0,0 +1,21 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc; + +/** Anything that can preallocate buffers given prior knowledge of the number of stored elements. */ +public interface Preallocable { + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + public void ensureCapacity(int expectedElements); +} diff --git a/src/main/java/com/carrotsearch/hppc/RamUsageEstimator.java b/src/main/java/com/carrotsearch/hppc/RamUsageEstimator.java new file mode 100755 index 00000000..907ea2e9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/RamUsageEstimator.java @@ -0,0 +1,162 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc; + +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.Map; + +/** + * Helper class that helps estimate memory usage + * + *

Mostly forked from Lucene tag releases/lucene-solr/8.5.1 + */ +final class RamUsageEstimator { + /** No instantiation. */ + private RamUsageEstimator() {} + + /** True, iff compressed references (oops) are enabled by this JVM */ + static final boolean COMPRESSED_REFS_ENABLED; + + /** Number of bytes this JVM uses to represent an object reference. */ + static final int NUM_BYTES_OBJECT_REF; + + /** Number of bytes to represent an object header (no fields, no alignments). */ + static final int NUM_BYTES_OBJECT_HEADER; + + /** Number of bytes to represent an array header (no content, but with alignments). */ + static final int NUM_BYTES_ARRAY_HEADER; + + /** + * A constant specifying the object alignment boundary inside the JVM. Objects will always take a + * full multiple of this constant, possibly wasting some space. + */ + static final int NUM_BYTES_OBJECT_ALIGNMENT; + + /** Sizes of primitive classes. */ + static final Map, Integer> primitiveSizes; + + static { + Map, Integer> primitiveSizesMap = new IdentityHashMap<>(); + primitiveSizesMap.put(boolean.class, 1); + primitiveSizesMap.put(byte.class, 1); + primitiveSizesMap.put(char.class, Character.BYTES); + primitiveSizesMap.put(short.class, Short.BYTES); + primitiveSizesMap.put(int.class, Integer.BYTES); + primitiveSizesMap.put(float.class, Float.BYTES); + primitiveSizesMap.put(double.class, Double.BYTES); + primitiveSizesMap.put(long.class, Long.BYTES); + + primitiveSizes = Collections.unmodifiableMap(primitiveSizesMap); + } + + static final boolean JRE_IS_64BIT; + + static final String MANAGEMENT_FACTORY_CLASS = "java.lang.management.ManagementFactory"; + static final String HOTSPOT_BEAN_CLASS = "com.sun.management.HotSpotDiagnosticMXBean"; + + static final String OS_ARCH = System.getProperty("os.arch"); + + // Initialize constants and try to collect information about the JVM internals. + static { + boolean is64Bit = false; + String datamodel = null; + try { + datamodel = System.getProperty("sun.arch.data.model"); + if (datamodel != null) { + is64Bit = datamodel.contains("64"); + } + } catch (SecurityException ignored) { + } + if (datamodel == null) { + is64Bit = OS_ARCH != null && OS_ARCH.contains("64"); + } + JRE_IS_64BIT = is64Bit; + if (JRE_IS_64BIT) { + // Try to get compressed oops and object alignment (the default seems to be 8 on Hotspot); + // (this only works on 64 bit, on 32 bits the alignment and reference size is fixed): + boolean compressedOops = false; + int objectAlignment = 8; + try { + final Class beanClazz = Class.forName(HOTSPOT_BEAN_CLASS); + // we use reflection for this, because the management factory is not part + // of Java 8's compact profile: + final Object hotSpotBean = + Class.forName(MANAGEMENT_FACTORY_CLASS) + .getMethod("getPlatformMXBean", Class.class) + .invoke(null, beanClazz); + if (hotSpotBean != null) { + final Method getVMOptionMethod = beanClazz.getMethod("getVMOption", String.class); + try { + final Object vmOption = getVMOptionMethod.invoke(hotSpotBean, "UseCompressedOops"); + compressedOops = + Boolean.parseBoolean( + vmOption.getClass().getMethod("getValue").invoke(vmOption).toString()); + } catch (ReflectiveOperationException | RuntimeException ignored) { + } + try { + final Object vmOption = getVMOptionMethod.invoke(hotSpotBean, "ObjectAlignmentInBytes"); + objectAlignment = + Integer.parseInt( + vmOption.getClass().getMethod("getValue").invoke(vmOption).toString()); + } catch (ReflectiveOperationException | RuntimeException ignored) { + } + } + } catch (ReflectiveOperationException | RuntimeException ignored) { + } + COMPRESSED_REFS_ENABLED = compressedOops; + NUM_BYTES_OBJECT_ALIGNMENT = objectAlignment; + // reference size is 4, if we have compressed oops: + NUM_BYTES_OBJECT_REF = COMPRESSED_REFS_ENABLED ? 4 : 8; + // "best guess" based on reference size: + NUM_BYTES_OBJECT_HEADER = 8 + NUM_BYTES_OBJECT_REF; + // array header is NUM_BYTES_OBJECT_HEADER + NUM_BYTES_INT, but aligned (object alignment): + NUM_BYTES_ARRAY_HEADER = (int) alignObjectSize(NUM_BYTES_OBJECT_HEADER + Integer.BYTES); + } else { + COMPRESSED_REFS_ENABLED = false; + NUM_BYTES_OBJECT_ALIGNMENT = 8; + NUM_BYTES_OBJECT_REF = 4; + NUM_BYTES_OBJECT_HEADER = 8; + // For 32 bit JVMs, no extra alignment of array header: + NUM_BYTES_ARRAY_HEADER = NUM_BYTES_OBJECT_HEADER + Integer.BYTES; + } + } + + /** Aligns an object size to be the next multiple of {@link #NUM_BYTES_OBJECT_ALIGNMENT}. */ + static long alignObjectSize(long size) { + size += (long) NUM_BYTES_OBJECT_ALIGNMENT - 1L; + return size - (size % NUM_BYTES_OBJECT_ALIGNMENT); + } + + /** + * Return used part of shallow size of any array. + * + * @param usedSize Size that array is actually used + */ + static long shallowUsedSizeOfArray(Object array, int usedSize) { + long size = NUM_BYTES_ARRAY_HEADER; + if (usedSize > 0) { + Class arrayElementClazz = array.getClass().getComponentType(); + if (arrayElementClazz.isPrimitive()) { + size += (long) usedSize * primitiveSizes.get(arrayElementClazz); + } else { + size += (long) NUM_BYTES_OBJECT_REF * usedSize; + } + } + return alignObjectSize(size); + } + + /** Return shallow size of any array. */ + static long shallowSizeOfArray(Object array) { + return shallowUsedSizeOfArray(array, Array.getLength(array)); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortArrayDeque.java b/src/main/java/com/carrotsearch/hppc/ShortArrayDeque.java new file mode 100755 index 00000000..9c1cf824 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortArrayDeque.java @@ -0,0 +1,776 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; + +import com.carrotsearch.hppc.cursors.ShortCursor; +import com.carrotsearch.hppc.predicates.ShortPredicate; +import com.carrotsearch.hppc.procedures.ShortProcedure; +import java.util.*; + +/** An array-backed {@link ShortDeque}. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java") +public class ShortArrayDeque extends AbstractShortCollection + implements ShortDeque, Preallocable, Cloneable, Accountable { + + /** Reuse the same strategy instance. */ + private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = + BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; + + /** Internal array for storing elements of the deque. */ + public short[] buffer = ShortArrayList.EMPTY_ARRAY; + + /** + * The index of the element at the head of the deque or an arbitrary number equal to tail if the + * deque is empty. + */ + public int head; + + /** The index at which the next element would be added to the tail of the deque. */ + public int tail; + + /** Buffer resizing strategy. */ + protected final ArraySizingStrategy resizer; + + /** New instance with sane defaults. */ + public ShortArrayDeque() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ShortArrayDeque(int expectedElements) { + this(expectedElements, DEFAULT_SIZING_STRATEGY); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public ShortArrayDeque(int expectedElements, ArraySizingStrategy resizer) { + assert resizer != null; + this.resizer = resizer; + ensureCapacity(expectedElements); + } + + /** + * Creates a new deque from elements of another container, appending elements at the end of the + * deque in the iteration order. + */ + public ShortArrayDeque(ShortContainer container) { + this(container.size()); + addLast(container); + } + + /** {@inheritDoc} */ + @Override + public void addFirst(short e1) { + int h = oneLeft(head, buffer.length); + if (h == tail) { + ensureBufferSpace(1); + h = oneLeft(head, buffer.length); + } + buffer[head = h] = e1; + } + + /** + * Vararg-signature method for adding elements at the front of this deque. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + * + * @param elements The elements to add. + */ + public final void addFirst(short... elements) { + ensureBufferSpace(elements.length); + for (short k : elements) { + addFirst(k); + } + } + + /** + * Inserts all elements from the given container to the front of this deque. + * + * @param container The container to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addFirst(ShortContainer container) { + int size = container.size(); + ensureBufferSpace(size); + + for (ShortCursor cursor : container) { + addFirst(cursor.value); + } + + return size; + } + + /** + * Inserts all elements from the given iterable to the front of this deque. + * + * @param iterable The iterable to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addFirst(Iterable iterable) { + int size = 0; + for (ShortCursor cursor : iterable) { + addFirst(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public void addLast(short e1) { + int t = oneRight(tail, buffer.length); + if (head == t) { + ensureBufferSpace(1); + t = oneRight(tail, buffer.length); + } + buffer[tail] = e1; + tail = t; + } + + /** + * Vararg-signature method for adding elements at the end of this deque. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + * + * @param elements The elements to iterate over. + */ + public final void addLast(short... elements) { + ensureBufferSpace(1); + for (short k : elements) { + addLast(k); + } + } + + /** + * Inserts all elements from the given container to the end of this deque. + * + * @param container The container to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addLast(ShortContainer container) { + int size = container.size(); + ensureBufferSpace(size); + + for (ShortCursor cursor : container) { + addLast(cursor.value); + } + + return size; + } + + /** + * Inserts all elements from the given iterable to the end of this deque. + * + * @param iterable The iterable to iterate over. + * @return Returns the number of elements actually added as a result of this call. + */ + public int addLast(Iterable iterable) { + int size = 0; + for (ShortCursor cursor : iterable) { + addLast(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public short removeFirst() { + assert size() > 0 : "The deque is empty."; + + final short result = buffer[head]; + buffer[head] = ((short) 0); + head = oneRight(head, buffer.length); + return result; + } + + /** {@inheritDoc} */ + @Override + public short removeLast() { + assert size() > 0 : "The deque is empty."; + + tail = oneLeft(tail, buffer.length); + final short result = buffer[tail]; + buffer[tail] = ((short) 0); + return result; + } + + /** {@inheritDoc} */ + @Override + public short getFirst() { + assert size() > 0 : "The deque is empty."; + + return buffer[head]; + } + + /** {@inheritDoc} */ + @Override + public short getLast() { + assert size() > 0 : "The deque is empty."; + + return buffer[oneLeft(tail, buffer.length)]; + } + + /** {@inheritDoc} */ + @Override + public int removeFirst(short e1) { + final int index = bufferIndexOf(e1); + if (index >= 0) removeAtBufferIndex(index); + return index; + } + + /** + * Return the index of the first (counting from head) element equal to e1. The index + * points to the {@link #buffer} array. + * + * @param e1 The element to look for. + * @return Returns the index of the first element equal to e1 or -1 if + * not found. + */ + public int bufferIndexOf(short e1) { + final int last = tail; + final int bufLen = buffer.length; + for (int i = head; i != last; i = oneRight(i, bufLen)) { + if (((e1) == (buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int removeLast(short e1) { + final int index = lastBufferIndexOf(e1); + if (index >= 0) { + removeAtBufferIndex(index); + } + return index; + } + + /** + * Return the index of the last (counting from tail) element equal to e1. The index + * points to the {@link #buffer} array. + * + * @param e1 The element to look for. + * @return Returns the index of the first element equal to e1 or -1 if + * not found. + */ + public int lastBufferIndexOf(short e1) { + final int bufLen = buffer.length; + final int last = oneLeft(head, bufLen); + for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) { + if (((e1) == (buffer[i]))) return i; + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(short e1) { + int removed = 0; + final int last = tail; + final int bufLen = buffer.length; + int from, to; + for (from = to = head; from != last; from = oneRight(from, bufLen)) { + if (((e1) == (buffer[from]))) { + buffer[from] = ((short) 0); + removed++; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = ((short) 0); + } + + to = oneRight(to, bufLen); + } + + tail = to; + return removed; + } + + /** + * Removes the element at index in the internal {#link {@link #buffer} array, + * returning its value. + * + * @param index Index of the element to remove. The index must be located between {@link #head} + * and {@link #tail} in modulo {@link #buffer} arithmetic. + */ + public void removeAtBufferIndex(int index) { + assert (head <= tail ? index >= head && index < tail : index >= head || index < tail) + : "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ")."; + + // Cache fields in locals (hopefully moved to registers). + final short[] buffer = this.buffer; + final int bufLen = buffer.length; + final int lastIndex = bufLen - 1; + final int head = this.head; + final int tail = this.tail; + + final int leftChunk = Math.abs(index - head) % bufLen; + final int rightChunk = Math.abs(tail - index) % bufLen; + + if (leftChunk < rightChunk) { + if (index >= head) { + System.arraycopy(buffer, head, buffer, head + 1, leftChunk); + } else { + System.arraycopy(buffer, 0, buffer, 1, index); + buffer[0] = buffer[lastIndex]; + System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head); + } + buffer[head] = ((short) 0); + this.head = oneRight(head, bufLen); + } else { + if (index < tail) { + System.arraycopy(buffer, index + 1, buffer, index, rightChunk); + } else { + System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index); + buffer[lastIndex] = buffer[0]; + System.arraycopy(buffer, 1, buffer, 0, tail); + } + buffer[tail] = ((short) 0); + this.tail = oneLeft(tail, bufLen); + } + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int size() { + if (head <= tail) return tail - head; + else return (tail - head + buffer.length); + } + + /** + * {@inheritDoc} + * + *

The internal array buffers are not released as a result of this call. + * + * @see #release() + */ + @Override + public void clear() { + if (head < tail) { + Arrays.fill(buffer, head, tail, ((short) 0)); + } else { + Arrays.fill(buffer, 0, tail, ((short) 0)); + Arrays.fill(buffer, head, buffer.length, ((short) 0)); + } + this.head = tail = 0; + } + + /** Release internal buffers of this deque and reallocate with the default buffer. */ + public void release() { + this.head = tail = 0; + buffer = ShortArrayList.EMPTY_ARRAY; + ensureBufferSpace(0); + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + ensureBufferSpace(expectedElements - size()); + } + + /** + * Ensures the internal buffer has enough free slots to store expectedAdditions. + * Increases internal buffer size if needed. + */ + protected void ensureBufferSpace(int expectedAdditions) { + final int bufferLen = buffer.length; + final int elementsCount = size(); + + if (elementsCount + expectedAdditions >= bufferLen) { + final int emptySlot = 1; // deque invariant: always an empty slot. + final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions); + assert newSize >= (elementsCount + expectedAdditions + emptySlot) + : "Resizer failed to" + + " return sensible new size: " + + newSize + + " <= " + + (elementsCount + expectedAdditions); + + try { + final short[] newBuffer = (new short[newSize]); + if (bufferLen > 0) { + toArray(newBuffer); + tail = elementsCount; + head = 0; + } + this.buffer = newBuffer; + } catch (OutOfMemoryError e) { + throw new BufferAllocationException( + "Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize); + } + } + } + + /** {@inheritDoc} */ + @Override + public short[] toArray() { + + final int size = size(); + return toArray((new short[size])); + } + + /** + * Copies elements of this deque to an array. The content of the target array is + * filled from index 0 (head of the queue) to index size() - 1 (tail of the queue). + * + * @param target The target array must be large enough to hold all elements. + * @return Returns the target argument for chaining. + */ + public short[] toArray(short[] target) { + assert target.length >= size() : "Target array must be >= " + size(); + + if (head < tail) { + // The contents is not wrapped around. Just copy. + System.arraycopy(buffer, head, target, 0, size()); + } else if (head > tail) { + // The contents is split. Merge elements from the following indexes: + // [head...buffer.length - 1][0, tail - 1] + final int rightCount = buffer.length - head; + System.arraycopy(buffer, head, target, 0, rightCount); + System.arraycopy(buffer, 0, target, rightCount, tail); + } + + return target; + } + + /** + * Clone this object. The returned clone will reuse the same hash function and array resizing + * strategy. + */ + @Override + public ShortArrayDeque clone() { + try { + + ShortArrayDeque cloned = (ShortArrayDeque) super.clone(); + cloned.buffer = buffer.clone(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Move one index to the left, wrapping around buffer. */ + protected static int oneLeft(int index, int modulus) { + if (index >= 1) { + return index - 1; + } + return modulus - 1; + } + + /** Move one index to the right, wrapping around buffer. */ + protected static int oneRight(int index, int modulus) { + if (index + 1 == modulus) { + return 0; + } + return index + 1; + } + + @Override + public long ramBytesAllocated() { + // int: head, tail + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES * 2 + + resizer.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(buffer); + } + + @Override + public long ramBytesUsed() { + // int: head, tail + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES * 2 + + resizer.ramBytesUsed() + + RamUsageEstimator.shallowUsedSizeOfArray(buffer, size()); + } + + /** An iterator implementation for {@link ObjectArrayDeque#iterator}. */ + private final class ValueIterator extends AbstractIterator { + private final ShortCursor cursor; + private int remaining; + + public ValueIterator() { + cursor = new ShortCursor(); + cursor.index = oneLeft(head, buffer.length); + this.remaining = size(); + } + + @Override + protected ShortCursor fetch() { + if (remaining == 0) { + return done(); + } + + remaining--; + cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)]; + return cursor; + } + } + + /** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */ + private final class DescendingValueIterator extends AbstractIterator { + private final ShortCursor cursor; + private int remaining; + + public DescendingValueIterator() { + cursor = new ShortCursor(); + cursor.index = tail; + this.remaining = size(); + } + + @Override + protected ShortCursor fetch() { + if (remaining == 0) return done(); + + remaining--; + cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)]; + return cursor; + } + } + + /** + * Returns a cursor over the values of this deque (in head to tail order). The iterator is + * implemented as a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in + * the deque's buffer) use the cursor's public fields. An example is shown below. + * + *

+   * for (IntValueCursor c : intDeque) {
+   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator iterator() { + return new ValueIterator(); + } + + /** + * Returns a cursor over the values of this deque (in tail to head order). The iterator is + * implemented as a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in + * the deque's buffer) use the cursor's public fields. An example is shown below. + * + *
+   * for (Iterator<IntCursor> i = intDeque.descendingIterator(); i.hasNext();) {
+   *   final IntCursor c = i.next();
+   *   System.out.println("buffer index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator descendingIterator() { + return new DescendingValueIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + forEach(procedure, head, tail); + return procedure; + } + + /** + * Applies procedure to a slice of the deque, fromIndex, inclusive, to + * toIndex, exclusive. + */ + private void forEach(ShortProcedure procedure, int fromIndex, final int toIndex) { + final short[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + procedure.apply(buffer[i]); + } + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + int fromIndex = head; + int toIndex = tail; + + final short[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + if (!predicate.apply(buffer[i])) { + break; + } + } + + return predicate; + } + + /** Applies procedure to all elements of this deque, tail to head. */ + @Override + public T descendingForEach(T procedure) { + descendingForEach(procedure, head, tail); + return procedure; + } + + /** + * Applies procedure to a slice of the deque, toIndex, exclusive, down + * to fromIndex, inclusive. + */ + private void descendingForEach(ShortProcedure procedure, int fromIndex, final int toIndex) { + if (fromIndex == toIndex) return; + + final short[] buffer = this.buffer; + int i = toIndex; + do { + i = oneLeft(i, buffer.length); + procedure.apply(buffer[i]); + } while (i != fromIndex); + } + + /** {@inheritDoc} */ + @Override + public T descendingForEach(T predicate) { + descendingForEach(predicate, head, tail); + return predicate; + } + + /** + * Applies predicate to a slice of the deque, toIndex, exclusive, down + * to fromIndex, inclusive or until the predicate returns false. + */ + private void descendingForEach(ShortPredicate predicate, int fromIndex, final int toIndex) { + if (fromIndex == toIndex) return; + + final short[] buffer = this.buffer; + int i = toIndex; + do { + i = oneLeft(i, buffer.length); + if (!predicate.apply(buffer[i])) { + break; + } + } while (i != fromIndex); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortPredicate predicate) { + final short[] buffer = this.buffer; + final int last = tail; + final int bufLen = buffer.length; + int removed = 0; + int from, to; + from = to = head; + try { + for (from = to = head; from != last; from = oneRight(from, bufLen)) { + if (predicate.apply(buffer[from])) { + buffer[from] = ((short) 0); + removed++; + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = ((short) 0); + } + + to = oneRight(to, bufLen); + } + } finally { + // Keep the deque in consistent state even if the predicate throws an exception. + for (; from != last; from = oneRight(from, bufLen)) { + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = ((short) 0); + } + + to = oneRight(to, bufLen); + } + tail = to; + } + + return removed; + } + + /** {@inheritDoc} */ + @Override + public boolean contains(short e) { + int fromIndex = head; + int toIndex = tail; + + final short[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + if (((e) == (buffer[i]))) { + return true; + } + } + + return false; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 1; + int fromIndex = head; + int toIndex = tail; + + final short[] buffer = this.buffer; + for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { + h = 31 * h + BitMixer.mix(this.buffer[i]); + } + return h; + } + + /** + * Returns true only if the other object is an instance of the same class and with + * the same elements. + */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Compare order-aligned elements against another {@link ShortDeque}. */ + protected boolean equalElements(ShortArrayDeque other) { + int max = size(); + if (other.size() != max) { + return false; + } + + Iterator i1 = this.iterator(); + Iterator i2 = other.iterator(); + + while (i1.hasNext() && i2.hasNext()) { + if (!((i1.next().value) == (i2.next().value))) { + return false; + } + } + + return !i1.hasNext() && !i2.hasNext(); + } + + /** Create a new deque by pushing a variable number of arguments to the end of it. */ + public static ShortArrayDeque from(short... elements) { + final ShortArrayDeque coll = new ShortArrayDeque(elements.length); + coll.addLast(elements); + return coll; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortArrayList.java b/src/main/java/com/carrotsearch/hppc/ShortArrayList.java new file mode 100755 index 00000000..cae87388 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortArrayList.java @@ -0,0 +1,579 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.ShortPredicate; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** An array-backed list of shorts. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java") +public class ShortArrayList extends AbstractShortCollection + implements ShortIndexedContainer, Preallocable, Cloneable, Accountable { + /** An immutable empty buffer (array). */ + public static final short[] EMPTY_ARRAY = new short[0]; + + ; + + /** Reuse the same strategy instance. */ + private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = + BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; + + /** + * Internal array for storing the list. The array may be larger than the current size ({@link + * #size()}). + */ + public short[] buffer = EMPTY_ARRAY; + + /** Current number of elements stored in {@link #buffer}. */ + public int elementsCount; + + /** Buffer resizing strategy. */ + protected final ArraySizingStrategy resizer; + + /** New instance with sane defaults. */ + public ShortArrayList() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ShortArrayList(int expectedElements) { + this(expectedElements, DEFAULT_SIZING_STRATEGY); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public ShortArrayList(int expectedElements, ArraySizingStrategy resizer) { + assert resizer != null; + this.resizer = resizer; + buffer = Arrays.copyOf(buffer, expectedElements); + } + + /** Creates a new list from the elements of another container in its iteration order. */ + public ShortArrayList(ShortContainer container) { + this(container.size()); + addAll(container); + } + + /** {@inheritDoc} */ + @Override + public void add(short e1) { + ensureBufferSpace(1); + buffer[elementsCount++] = e1; + } + + /** + * Appends two elements at the end of the list. To add more than two elements, use add + * (vararg-version) or access the buffer directly (tight loop). + */ + public void add(short e1, short e2) { + ensureBufferSpace(2); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + } + + /** Add all elements from a range of given array to the list. */ + public void add(short[] elements, int start, int length) { + assert length >= 0 : "Length must be >= 0"; + + ensureBufferSpace(length); + System.arraycopy(elements, start, buffer, elementsCount, length); + elementsCount += length; + } + + /** + * Vararg-signature method for adding elements at the end of the list. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + */ + public final void add(short... elements) { + add(elements, 0, elements.length); + } + + /** Adds all elements from another container. */ + public int addAll(ShortContainer container) { + final int size = container.size(); + ensureBufferSpace(size); + + for (ShortCursor cursor : container) { + add(cursor.value); + } + + return size; + } + + /** Adds all elements from another iterable. */ + public int addAll(Iterable iterable) { + int size = 0; + for (ShortCursor cursor : iterable) { + add(cursor.value); + size++; + } + return size; + } + + /** {@inheritDoc} */ + @Override + public void insert(int index, short e1) { + assert (index >= 0 && index <= size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + "]."; + + ensureBufferSpace(1); + System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index); + buffer[index] = e1; + elementsCount++; + } + + /** {@inheritDoc} */ + @Override + public short get(int index) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + return buffer[index]; + } + + /** {@inheritDoc} */ + @Override + public short set(int index, short e1) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + final short v = buffer[index]; + buffer[index] = e1; + return v; + } + + /** {@inheritDoc} */ + @Override + public short removeAt(int index) { + assert (index >= 0 && index < size()) + : "Index " + index + " out of bounds [" + 0 + ", " + size() + ")."; + + final short v = buffer[index]; + System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index); + + return v; + } + + /** {@inheritDoc} */ + @Override + public short removeLast() { + assert elementsCount > 0; + + final short v = buffer[--elementsCount]; + + return v; + } + + /** {@inheritDoc} */ + @Override + public void removeRange(int fromIndex, int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex); + final int count = toIndex - fromIndex; + elementsCount -= count; + } + + /** {@inheritDoc} */ + @Override + public boolean removeElement(short e1) { + return removeFirst(e1) != -1; + } + + /** {@inheritDoc} */ + @Override + public int removeFirst(short e1) { + final int index = indexOf(e1); + if (index >= 0) removeAt(index); + return index; + } + + /** {@inheritDoc} */ + @Override + public int removeLast(short e1) { + final int index = lastIndexOf(e1); + if (index >= 0) removeAt(index); + return index; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(short e1) { + int to = 0; + for (int from = 0; from < elementsCount; from++) { + if (((e1) == (buffer[from]))) { + continue; + } + if (to != from) { + buffer[to] = buffer[from]; + } + to++; + } + final int deleted = elementsCount - to; + this.elementsCount = to; + + return deleted; + } + + /** {@inheritDoc} */ + @Override + public boolean contains(short e1) { + return indexOf(e1) >= 0; + } + + /** {@inheritDoc} */ + @Override + public int indexOf(short e1) { + for (int i = 0; i < elementsCount; i++) { + if (((e1) == (buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public int lastIndexOf(short e1) { + for (int i = elementsCount - 1; i >= 0; i--) { + if (((e1) == (buffer[i]))) { + return i; + } + } + + return -1; + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return elementsCount == 0; + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + final int bufferLen = (buffer == null ? 0 : buffer.length); + if (expectedElements > bufferLen) { + ensureBufferSpace(expectedElements - size()); + } + } + + /** + * Ensures the internal buffer has enough free slots to store expectedAdditions. + * Increases internal buffer size if needed. + */ + protected void ensureBufferSpace(int expectedAdditions) { + final int bufferLen = (buffer == null ? 0 : buffer.length); + if (elementsCount + expectedAdditions > bufferLen) { + final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions); + assert newSize >= elementsCount + expectedAdditions + : "Resizer failed to" + + " return sensible new size: " + + newSize + + " <= " + + (elementsCount + expectedAdditions); + + this.buffer = Arrays.copyOf(buffer, newSize); + } + } + + /** + * Truncate or expand the list to the new size. If the list is truncated, the buffer will not be + * reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated + * values will be reset to the default value (zero). If the list is expanded, the elements beyond + * the current size are initialized with JVM-defaults (zero or null values). + */ + public void resize(int newSize) { + if (newSize <= buffer.length) { + if (newSize < elementsCount) { + Arrays.fill(buffer, newSize, elementsCount, ((short) 0)); + } else { + Arrays.fill(buffer, elementsCount, newSize, ((short) 0)); + } + } else { + ensureCapacity(newSize); + } + this.elementsCount = newSize; + } + + /** {@inheritDoc} */ + @Override + public int size() { + return elementsCount; + } + + /** Trim the internal buffer to the current size. */ + public void trimToSize() { + if (size() != this.buffer.length) { + this.buffer = toArray(); + } + } + + /** + * Sets the number of stored elements to zero. Releases and initializes the internal storage array + * to default values. To clear the list without cleaning the buffer, simply set the {@link + * #elementsCount} field to zero. + */ + @Override + public void clear() { + Arrays.fill(buffer, 0, elementsCount, ((short) 0)); + this.elementsCount = 0; + } + + /** Sets the number of stored elements to zero and releases the internal storage array. */ + @Override + public void release() { + this.buffer = EMPTY_ARRAY; + this.elementsCount = 0; + } + + /** + * {@inheritDoc} + * + *

The returned array is sized to match exactly the number of elements of the stack. + */ + @Override + public short[] toArray() { + + return Arrays.copyOf(buffer, elementsCount); + } + + /** {@inheritDoc} */ + @Override + public ShortIndexedContainer sort() { + Arrays.sort(buffer, 0, elementsCount); + return this; + } + + /** {@inheritDoc} */ + @Override + public ShortIndexedContainer reverse() { + for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) { + short tmp = buffer[i]; + buffer[i] = buffer[j]; + buffer[j] = tmp; + } + return this; + } + + /** + * Clone this object. The returned clone will reuse the same hash function and array resizing + * strategy. + */ + @Override + public ShortArrayList clone() { + try { + + final ShortArrayList cloned = (ShortArrayList) super.clone(); + cloned.buffer = buffer.clone(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 1, max = elementsCount; + for (int i = 0; i < max; i++) { + h = 31 * h + BitMixer.mix(this.buffer[i]); + } + return h; + } + + /** + * Returns true only if the other object is an instance of the same class and with + * the same elements. + */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Compare index-aligned elements against another {@link ShortIndexedContainer}. */ + protected boolean equalElements(ShortArrayList other) { + int max = size(); + if (other.size() != max) { + return false; + } + + for (int i = 0; i < max; i++) { + if (!((get(i)) == (other.get(i)))) { + return false; + } + } + + return true; + } + + @Override + public long ramBytesAllocated() { + // int: elementsCount + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES + + resizer.ramBytesAllocated() + + RamUsageEstimator.shallowSizeOfArray(buffer); + } + + @Override + public long ramBytesUsed() { + // int: elementsCount + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + Integer.BYTES + + resizer.ramBytesUsed() + + RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount); + } + + /** An iterator implementation for {@link ShortArrayList#iterator}. */ + static final class ValueIterator extends AbstractIterator { + private final ShortCursor cursor; + + private final short[] buffer; + private final int size; + + public ValueIterator(short[] buffer, int size) { + this.cursor = new ShortCursor(); + this.cursor.index = -1; + this.size = size; + this.buffer = buffer; + } + + @Override + protected ShortCursor fetch() { + if (cursor.index + 1 == size) return done(); + + cursor.value = buffer[++cursor.index]; + return cursor; + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new ValueIterator(buffer, size()); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + return forEach(procedure, 0, size()); + } + + /** + * Applies procedure to a slice of the list, fromIndex, inclusive, to + * toIndex, exclusive. + */ + public T forEach(T procedure, int fromIndex, final int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + final short[] buffer = this.buffer; + for (int i = fromIndex; i < toIndex; i++) { + procedure.apply(buffer[i]); + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortPredicate predicate) { + final short[] buffer = this.buffer; + final int elementsCount = this.elementsCount; + int to = 0; + int from = 0; + try { + for (; from < elementsCount; from++) { + if (predicate.apply(buffer[from])) { + buffer[from] = ((short) 0); + continue; + } + + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = ((short) 0); + } + to++; + } + } finally { + // Keep the list in a consistent state, even if the predicate throws an exception. + for (; from < elementsCount; from++) { + if (to != from) { + buffer[to] = buffer[from]; + buffer[from] = ((short) 0); + } + to++; + } + + this.elementsCount = to; + } + + return elementsCount - to; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + return forEach(predicate, 0, size()); + } + + /** + * Applies predicate to a slice of the list, fromIndex, inclusive, to + * toIndex, exclusive, or until predicate returns false. + */ + public T forEach(T predicate, int fromIndex, final int toIndex) { + assert (fromIndex >= 0 && fromIndex <= size()) + : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ")."; + assert (toIndex >= 0 && toIndex <= size()) + : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "]."; + assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex; + + final short[] buffer = this.buffer; + for (int i = fromIndex; i < toIndex; i++) { + if (!predicate.apply(buffer[i])) break; + } + + return predicate; + } + + /** + * Create a list from a variable number of arguments or an array of short. The + * elements are copied from the argument to the internal buffer. + */ + public static ShortArrayList from(short... elements) { + final ShortArrayList list = new ShortArrayList(elements.length); + list.add(elements); + return list; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortBufferVisualizer.java b/src/main/java/com/carrotsearch/hppc/ShortBufferVisualizer.java new file mode 100755 index 00000000..ce873652 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortBufferVisualizer.java @@ -0,0 +1,33 @@ +package com.carrotsearch.hppc; + +/** + * Reused buffer visualization routines. + * + * @see ShortSet#visualizeKeyDistribution(int) + * @see ShortVTypeMap#visualizeKeyDistribution(int) + */ +class ShortBufferVisualizer { + static String visualizeKeyDistribution(short[] buffer, int max, int characters) { + final StringBuilder b = new StringBuilder(); + final char[] chars = ".123456789X".toCharArray(); + for (int i = 1, start = -1; i <= characters; i++) { + int end = (int) ((long) i * max / characters); + + if (start + 1 <= end) { + int taken = 0; + int slots = 0; + for (int slot = start + 1; slot <= end; slot++, slots++) { + if (!((buffer[slot]) == 0)) { + taken++; + } + } + b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]); + start = end; + } + } + while (b.length() < characters) { + b.append(' '); + } + return b.toString(); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortByteAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ShortByteAssociativeContainer.java new file mode 100755 index 00000000..27f4953d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortByteAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see ShortContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface ShortByteAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(short key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortBytePredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ShortByteProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ShortBytePredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public ShortCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public ByteContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortByteHashMap.java b/src/main/java/com/carrotsearch/hppc/ShortByteHashMap.java new file mode 100755 index 00000000..049da077 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortByteHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of short to byte, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class ShortByteHashMap implements ShortByteMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public short[] keys; + + /** The array holding values. */ + public byte[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public ShortByteHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ShortByteHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ShortByteHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ShortByteHashMap(ShortByteAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public byte put(short key, byte value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + byte previousValue = hasEmptyKey ? values[mask + 1] : ((byte) 0); + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final byte previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return ((byte) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(ShortByteAssociativeContainer container) { + final int count = size(); + for (ShortByteCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (ShortByteCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public byte putOrAdd(short key, byte putValue, byte incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((byte) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public byte addTo(short key, byte incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public byte remove(short key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return ((byte) 0); + } + hasEmptyKey = false; + byte previousValue = values[mask + 1]; + values[mask + 1] = ((byte) 0); + return previousValue; + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final byte previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return ((byte) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof ShortLookupContainer) { + if (hasEmptyKey && other.contains(((short) 0))) { + hasEmptyKey = false; + values[mask + 1] = ((byte) 0); + } + + final short[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + short existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (ShortCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortBytePredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(((short) 0), values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = ((byte) 0); + } + } + + final short[] keys = this.keys; + final byte[] values = this.values; + for (int slot = 0; slot <= mask; ) { + short existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(((short) 0))) { + hasEmptyKey = false; + values[mask + 1] = ((byte) 0); + } + } + + final short[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + short existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public byte get(short key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : ((byte) 0); + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return ((byte) 0); + } + } + + /** {@inheritDoc} */ + @Override + public byte getOrDefault(short key, byte defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(short key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(short key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public byte indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public byte indexReplace(int index, byte newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + byte previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, short key, byte value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public byte indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + byte previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = ((byte) 0); + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, ((short) 0)); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (ShortByteCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(ShortByteHashMap other) { + if (other.size() != size()) { + return false; + } + + for (ShortByteCursor c : other) { + short key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final short[] prevKeys = this.keys; + final byte[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final ShortByteCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new ShortByteCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortByteCursor fetch() { + final int mask = ShortByteHashMap.this.mask; + while (index <= mask) { + short existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = ((short) 0); + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final short[] keys = this.keys; + final byte[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(((short) 0), values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final short[] keys = this.keys; + final byte[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(((short) 0), values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractShortCollection implements ShortLookupContainer { + private final ShortByteHashMap owner = ShortByteHashMap.this; + + @Override + public boolean contains(short e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((ShortByteProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((ShortBytePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final short e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final ShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new ShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortCursor fetch() { + final int mask = ShortByteHashMap.this.mask; + while (index <= mask) { + short existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = ((short) 0); + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public ByteCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractByteCollection { + private final ShortByteHashMap owner = ShortByteHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(byte value) { + for (ShortByteCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (ShortByteCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (ShortByteCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final byte e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final BytePredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ByteCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new ByteCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ByteCursor fetch() { + final int mask = ShortByteHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public ShortByteHashMap clone() { + try { + + ShortByteHashMap cloned = (ShortByteHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (ShortByteCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return ShortBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ShortByteHashMap from(short[] keys, byte[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ShortByteHashMap map = new ShortByteHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(short key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(short[] fromKeys, byte[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final short[] keys = this.keys; + final byte[] values = this.values; + final int mask = this.mask; + short existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + short[] prevKeys = this.keys; + byte[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new short[arraySize + emptyElementSlot]); + this.values = (new byte[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, short pendingKey, byte pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final short[] prevKeys = this.keys; + final byte[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final short[] keys = this.keys; + final byte[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final short existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = ((short) 0); + values[gapSlot] = ((byte) 0); + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortByteMap.java b/src/main/java/com/carrotsearch/hppc/ShortByteMap.java new file mode 100755 index 00000000..dfe9a67a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortByteMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ShortByteCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface ShortByteMap extends ShortByteAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public byte get(short key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public byte getOrDefault(short key, byte defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public byte put(short key, byte value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(short key, byte value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(ShortByteAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public byte putOrAdd(short key, byte putValue, byte incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public byte addTo(short key, byte additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public byte remove(short key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link ShortByteMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(short key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public byte indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public byte indexReplace(int index, byte newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, short key, byte value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public byte indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortCharAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ShortCharAssociativeContainer.java new file mode 100755 index 00000000..3ab6c85d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortCharAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see ShortContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface ShortCharAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(short key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortCharPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ShortCharProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ShortCharPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public ShortCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public CharContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortCharHashMap.java b/src/main/java/com/carrotsearch/hppc/ShortCharHashMap.java new file mode 100755 index 00000000..cb29c12e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortCharHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of short to char, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class ShortCharHashMap implements ShortCharMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public short[] keys; + + /** The array holding values. */ + public char[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public ShortCharHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ShortCharHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ShortCharHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ShortCharHashMap(ShortCharAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public char put(short key, char value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + char previousValue = hasEmptyKey ? values[mask + 1] : ((char) 0); + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final char previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return ((char) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(ShortCharAssociativeContainer container) { + final int count = size(); + for (ShortCharCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (ShortCharCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public char putOrAdd(short key, char putValue, char incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((char) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public char addTo(short key, char incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public char remove(short key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return ((char) 0); + } + hasEmptyKey = false; + char previousValue = values[mask + 1]; + values[mask + 1] = ((char) 0); + return previousValue; + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final char previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return ((char) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof ShortLookupContainer) { + if (hasEmptyKey && other.contains(((short) 0))) { + hasEmptyKey = false; + values[mask + 1] = ((char) 0); + } + + final short[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + short existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (ShortCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortCharPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(((short) 0), values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = ((char) 0); + } + } + + final short[] keys = this.keys; + final char[] values = this.values; + for (int slot = 0; slot <= mask; ) { + short existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(((short) 0))) { + hasEmptyKey = false; + values[mask + 1] = ((char) 0); + } + } + + final short[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + short existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public char get(short key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : ((char) 0); + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return ((char) 0); + } + } + + /** {@inheritDoc} */ + @Override + public char getOrDefault(short key, char defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(short key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(short key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public char indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public char indexReplace(int index, char newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + char previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, short key, char value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public char indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + char previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = ((char) 0); + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, ((short) 0)); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (ShortCharCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(ShortCharHashMap other) { + if (other.size() != size()) { + return false; + } + + for (ShortCharCursor c : other) { + short key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final short[] prevKeys = this.keys; + final char[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final ShortCharCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new ShortCharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortCharCursor fetch() { + final int mask = ShortCharHashMap.this.mask; + while (index <= mask) { + short existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = ((short) 0); + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final short[] keys = this.keys; + final char[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(((short) 0), values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final short[] keys = this.keys; + final char[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(((short) 0), values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractShortCollection implements ShortLookupContainer { + private final ShortCharHashMap owner = ShortCharHashMap.this; + + @Override + public boolean contains(short e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((ShortCharProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((ShortCharPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final short e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final ShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new ShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortCursor fetch() { + final int mask = ShortCharHashMap.this.mask; + while (index <= mask) { + short existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = ((short) 0); + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public CharCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractCharCollection { + private final ShortCharHashMap owner = ShortCharHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(char value) { + for (ShortCharCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (ShortCharCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (ShortCharCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final char e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final CharPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final CharCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new CharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharCursor fetch() { + final int mask = ShortCharHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public ShortCharHashMap clone() { + try { + + ShortCharHashMap cloned = (ShortCharHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (ShortCharCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return ShortBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ShortCharHashMap from(short[] keys, char[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ShortCharHashMap map = new ShortCharHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(short key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(short[] fromKeys, char[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final short[] keys = this.keys; + final char[] values = this.values; + final int mask = this.mask; + short existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + short[] prevKeys = this.keys; + char[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new short[arraySize + emptyElementSlot]); + this.values = (new char[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, short pendingKey, char pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final short[] prevKeys = this.keys; + final char[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final short[] keys = this.keys; + final char[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final short existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = ((short) 0); + values[gapSlot] = ((char) 0); + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortCharMap.java b/src/main/java/com/carrotsearch/hppc/ShortCharMap.java new file mode 100755 index 00000000..17bd928b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortCharMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ShortCharCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface ShortCharMap extends ShortCharAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public char get(short key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public char getOrDefault(short key, char defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public char put(short key, char value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(short key, char value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(ShortCharAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public char putOrAdd(short key, char putValue, char incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public char addTo(short key, char additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public char remove(short key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link ShortCharMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(short key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public char indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public char indexReplace(int index, char newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, short key, char value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public char indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortCollection.java b/src/main/java/com/carrotsearch/hppc/ShortCollection.java new file mode 100755 index 00000000..372dfca5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortCollection.java @@ -0,0 +1,64 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.predicates.ShortPredicate; + +/** + * A collection allows basic, efficient operations on sets of elements (difference and + * intersection). + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java") +public interface ShortCollection extends ShortContainer { + /** + * Removes all occurrences of e from this collection. + * + * @param e Element to be removed from this collection, if present. + * @return The number of removed elements as a result of this call. + */ + public int removeAll(short e); + + /** + * Removes all elements in this collection that are present in c. + * + * @return Returns the number of removed elements. + */ + public int removeAll(ShortLookupContainer c); + + /** + * Removes all elements in this collection for which the given predicate returns true + * . + * + * @return Returns the number of removed elements. + */ + public int removeAll(ShortPredicate predicate); + + /** + * Keeps all elements in this collection that are present in c. Runs in time + * proportional to the number of elements in this collection. Equivalent of sets intersection. + * + * @return Returns the number of removed elements. + */ + public int retainAll(ShortLookupContainer c); + + /** + * Keeps all elements in this collection for which the given predicate returns true. + * + * @return Returns the number of removed elements. + */ + public int retainAll(ShortPredicate predicate); + + /** + * Removes all elements from this collection. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortContainer.java b/src/main/java/com/carrotsearch/hppc/ShortContainer.java new file mode 100755 index 00000000..f425a1fe --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortContainer.java @@ -0,0 +1,76 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ShortCursor; +import com.carrotsearch.hppc.predicates.ShortPredicate; +import com.carrotsearch.hppc.procedures.ShortProcedure; +import java.util.Iterator; + +/** A generic container holding shorts. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java") +public interface ShortContainer extends Iterable { + /** + * Returns an iterator to a cursor traversing the collection. The order of traversal is not + * defined. More than one cursor may be active at a time. The behavior of iterators is undefined + * if structural changes are made to the underlying collection. + * + *

The iterator is implemented as a cursor and it returns the same cursor instance on + * every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current + * list's value (or index in the list) use the cursor's public fields. An example is shown below. + * + *

+   * for (ShortCursor<short> c : container) {
+   *   System.out.println("index=" + c.index + " value=" + c.value);
+   * }
+   * 
+ */ + public Iterator iterator(); + + /** + * Lookup a given element in the container. This operation has no speed guarantees (may be linear + * with respect to the size of this container). + * + * @return Returns true if this container has an element equal to e. + */ + public boolean contains(short e); + + /** + * Return the current number of elements in this container. The time for calculating the + * container's size may take O(n) time, although implementing classes should try to + * maintain the current size and return in constant time. + */ + public int size(); + + /** Shortcut for size() == 0. */ + public boolean isEmpty(); + + /** + * Copies all elements of this container to an array. + * + *

The returned array is always a copy, regardless of the storage used by the container. + */ + public short[] toArray(); + + /** + * Applies a procedure to all container elements. Returns the argument (any subclass + * of {@link ShortProcedure}. This lets the caller to call methods of the argument by chaining the + * call (even if the argument is an anonymous type) to retrieve computed values, for example + * (IntContainer): + * + *

+   * int count = container.forEach(new IntProcedure() {
+   *   int count; // this is a field declaration in an anonymous class.
+   *
+   *   public void apply(int value) {
+   *     count++;
+   *   }
+   * }).count;
+   * 
+ */ + public T forEach(T procedure); + + /** + * Applies a predicate to container elements as long, as the predicate returns + * true. The iteration is interrupted otherwise. + */ + public T forEach(T predicate); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortDeque.java b/src/main/java/com/carrotsearch/hppc/ShortDeque.java new file mode 100755 index 00000000..244b6a6a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortDeque.java @@ -0,0 +1,77 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ShortCursor; +import com.carrotsearch.hppc.predicates.ShortPredicate; +import com.carrotsearch.hppc.procedures.ShortProcedure; +import java.util.Deque; +import java.util.Iterator; + +/** + * A linear collection that supports element insertion and removal at both ends. + * + * @see Deque + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java") +public interface ShortDeque extends ShortCollection { + /** + * Removes the first element that equals e. + * + * @return The deleted element's index or -1 if the element was not found. + */ + public int removeFirst(short e); + + /** + * Removes the last element that equals e. + * + * @return The deleted element's index or -1 if the element was not found. + */ + public int removeLast(short e); + + /** Inserts the specified element at the front of this deque. */ + public void addFirst(short e); + + /** Inserts the specified element at the end of this deque. */ + public void addLast(short e); + + /** + * Retrieves and removes the first element of this deque. + * + * @return the head (first) element of this deque. + */ + public short removeFirst(); + + /** + * Retrieves and removes the last element of this deque. + * + * @return the tail of this deque. + */ + public short removeLast(); + + /** + * Retrieves the first element of this deque but does not remove it. + * + * @return the head of this deque. + */ + public short getFirst(); + + /** + * Retrieves the last element of this deque but does not remove it. + * + * @return the head of this deque. + */ + public short getLast(); + + /** + * @return An iterator over elements in this deque in tail-to-head order. + */ + public Iterator descendingIterator(); + + /** Applies a procedure to all elements in tail-to-head order. */ + public T descendingForEach(T procedure); + + /** + * Applies a predicate to container elements as long, as the predicate returns + * true. The iteration is interrupted otherwise. + */ + public T descendingForEach(T predicate); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortDoubleAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ShortDoubleAssociativeContainer.java new file mode 100755 index 00000000..0155b8a3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortDoubleAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see ShortContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface ShortDoubleAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *
+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(short key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortDoublePredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ShortDoubleProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ShortDoublePredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public ShortCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public DoubleContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/ShortDoubleHashMap.java new file mode 100755 index 00000000..4bf50582 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortDoubleHashMap.java @@ -0,0 +1,1082 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of short to double, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class ShortDoubleHashMap implements ShortDoubleMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public short[] keys; + + /** The array holding values. */ + public double[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public ShortDoubleHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ShortDoubleHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ShortDoubleHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ShortDoubleHashMap(ShortDoubleAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public double put(short key, double value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + double previousValue = hasEmptyKey ? values[mask + 1] : 0d; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final double previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0d; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(ShortDoubleAssociativeContainer container) { + final int count = size(); + for (ShortDoubleCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (ShortDoubleCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public double putOrAdd(short key, double putValue, double incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((double) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public double addTo(short key, double incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public double remove(short key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return 0d; + } + hasEmptyKey = false; + double previousValue = values[mask + 1]; + values[mask + 1] = 0d; + return previousValue; + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final double previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0d; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof ShortLookupContainer) { + if (hasEmptyKey && other.contains(((short) 0))) { + hasEmptyKey = false; + values[mask + 1] = 0d; + } + + final short[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + short existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (ShortCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortDoublePredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(((short) 0), values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0d; + } + } + + final short[] keys = this.keys; + final double[] values = this.values; + for (int slot = 0; slot <= mask; ) { + short existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(((short) 0))) { + hasEmptyKey = false; + values[mask + 1] = 0d; + } + } + + final short[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + short existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public double get(short key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : 0d; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0d; + } + } + + /** {@inheritDoc} */ + @Override + public double getOrDefault(short key, double defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(short key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(short key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public double indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public double indexReplace(int index, double newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + double previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, short key, double value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public double indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + double previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0d; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, ((short) 0)); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (ShortDoubleCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(ShortDoubleHashMap other) { + if (other.size() != size()) { + return false; + } + + for (ShortDoubleCursor c : other) { + short key = c.key; + if (!containsKey(key) + || !(Double.doubleToLongBits(c.value) == Double.doubleToLongBits(get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final short[] prevKeys = this.keys; + final double[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final ShortDoubleCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new ShortDoubleCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortDoubleCursor fetch() { + final int mask = ShortDoubleHashMap.this.mask; + while (index <= mask) { + short existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = ((short) 0); + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final short[] keys = this.keys; + final double[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(((short) 0), values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final short[] keys = this.keys; + final double[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(((short) 0), values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractShortCollection implements ShortLookupContainer { + private final ShortDoubleHashMap owner = ShortDoubleHashMap.this; + + @Override + public boolean contains(short e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((ShortDoubleProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((ShortDoublePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final short e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final ShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new ShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortCursor fetch() { + final int mask = ShortDoubleHashMap.this.mask; + while (index <= mask) { + short existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = ((short) 0); + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public DoubleCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractDoubleCollection { + private final ShortDoubleHashMap owner = ShortDoubleHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(double value) { + for (ShortDoubleCursor c : owner) { + if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (ShortDoubleCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (ShortDoubleCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final double e) { + return owner.removeAll( + (key, value) -> (Double.doubleToLongBits(e) == Double.doubleToLongBits(value))); + } + + @Override + public int removeAll(final DoublePredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final DoubleCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new DoubleCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected DoubleCursor fetch() { + final int mask = ShortDoubleHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public ShortDoubleHashMap clone() { + try { + + ShortDoubleHashMap cloned = (ShortDoubleHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (ShortDoubleCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return ShortBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ShortDoubleHashMap from(short[] keys, double[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ShortDoubleHashMap map = new ShortDoubleHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(short key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(short[] fromKeys, double[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final short[] keys = this.keys; + final double[] values = this.values; + final int mask = this.mask; + short existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + short[] prevKeys = this.keys; + double[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new short[arraySize + emptyElementSlot]); + this.values = (new double[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, short pendingKey, double pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final short[] prevKeys = this.keys; + final double[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final short[] keys = this.keys; + final double[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final short existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = ((short) 0); + values[gapSlot] = 0d; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortDoubleMap.java b/src/main/java/com/carrotsearch/hppc/ShortDoubleMap.java new file mode 100755 index 00000000..8d3ac5f8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortDoubleMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ShortDoubleCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface ShortDoubleMap extends ShortDoubleAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public double get(short key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public double getOrDefault(short key, double defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public double put(short key, double value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(short key, double value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(ShortDoubleAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public double putOrAdd(short key, double putValue, double incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public double addTo(short key, double additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public double remove(short key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link ShortDoubleMap} and both objects contains exactly the + * same key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(short key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public double indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public double indexReplace(int index, double newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, short key, double value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public double indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortFloatAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ShortFloatAssociativeContainer.java new file mode 100755 index 00000000..f6a2bf72 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortFloatAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see ShortContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface ShortFloatAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(short key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortFloatPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ShortFloatProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ShortFloatPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public ShortCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public FloatContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/ShortFloatHashMap.java new file mode 100755 index 00000000..9383ebab --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortFloatHashMap.java @@ -0,0 +1,1081 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of short to float, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class ShortFloatHashMap implements ShortFloatMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public short[] keys; + + /** The array holding values. */ + public float[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public ShortFloatHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ShortFloatHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ShortFloatHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ShortFloatHashMap(ShortFloatAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public float put(short key, float value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + float previousValue = hasEmptyKey ? values[mask + 1] : 0f; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final float previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0f; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(ShortFloatAssociativeContainer container) { + final int count = size(); + for (ShortFloatCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (ShortFloatCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public float putOrAdd(short key, float putValue, float incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((float) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public float addTo(short key, float incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public float remove(short key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return 0f; + } + hasEmptyKey = false; + float previousValue = values[mask + 1]; + values[mask + 1] = 0f; + return previousValue; + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final float previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0f; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof ShortLookupContainer) { + if (hasEmptyKey && other.contains(((short) 0))) { + hasEmptyKey = false; + values[mask + 1] = 0f; + } + + final short[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + short existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (ShortCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortFloatPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(((short) 0), values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0f; + } + } + + final short[] keys = this.keys; + final float[] values = this.values; + for (int slot = 0; slot <= mask; ) { + short existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(((short) 0))) { + hasEmptyKey = false; + values[mask + 1] = 0f; + } + } + + final short[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + short existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public float get(short key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : 0f; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0f; + } + } + + /** {@inheritDoc} */ + @Override + public float getOrDefault(short key, float defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(short key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(short key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public float indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public float indexReplace(int index, float newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + float previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, short key, float value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public float indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + float previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0f; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, ((short) 0)); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (ShortFloatCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(ShortFloatHashMap other) { + if (other.size() != size()) { + return false; + } + + for (ShortFloatCursor c : other) { + short key = c.key; + if (!containsKey(key) || !(Float.floatToIntBits(c.value) == Float.floatToIntBits(get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final short[] prevKeys = this.keys; + final float[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final ShortFloatCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new ShortFloatCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortFloatCursor fetch() { + final int mask = ShortFloatHashMap.this.mask; + while (index <= mask) { + short existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = ((short) 0); + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final short[] keys = this.keys; + final float[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(((short) 0), values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final short[] keys = this.keys; + final float[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(((short) 0), values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractShortCollection implements ShortLookupContainer { + private final ShortFloatHashMap owner = ShortFloatHashMap.this; + + @Override + public boolean contains(short e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((ShortFloatProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((ShortFloatPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final short e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final ShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new ShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortCursor fetch() { + final int mask = ShortFloatHashMap.this.mask; + while (index <= mask) { + short existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = ((short) 0); + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public FloatCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractFloatCollection { + private final ShortFloatHashMap owner = ShortFloatHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(float value) { + for (ShortFloatCursor c : owner) { + if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (ShortFloatCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (ShortFloatCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final float e) { + return owner.removeAll( + (key, value) -> (Float.floatToIntBits(e) == Float.floatToIntBits(value))); + } + + @Override + public int removeAll(final FloatPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final FloatCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new FloatCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected FloatCursor fetch() { + final int mask = ShortFloatHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public ShortFloatHashMap clone() { + try { + + ShortFloatHashMap cloned = (ShortFloatHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (ShortFloatCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return ShortBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ShortFloatHashMap from(short[] keys, float[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ShortFloatHashMap map = new ShortFloatHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(short key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(short[] fromKeys, float[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final short[] keys = this.keys; + final float[] values = this.values; + final int mask = this.mask; + short existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + short[] prevKeys = this.keys; + float[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new short[arraySize + emptyElementSlot]); + this.values = (new float[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, short pendingKey, float pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final short[] prevKeys = this.keys; + final float[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final short[] keys = this.keys; + final float[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final short existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = ((short) 0); + values[gapSlot] = 0f; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortFloatMap.java b/src/main/java/com/carrotsearch/hppc/ShortFloatMap.java new file mode 100755 index 00000000..d09dac18 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortFloatMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ShortFloatCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface ShortFloatMap extends ShortFloatAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public float get(short key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public float getOrDefault(short key, float defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public float put(short key, float value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(short key, float value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(ShortFloatAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public float putOrAdd(short key, float putValue, float incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public float addTo(short key, float additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public float remove(short key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link ShortFloatMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(short key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public float indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public float indexReplace(int index, float newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, short key, float value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public float indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortHashSet.java b/src/main/java/com/carrotsearch/hppc/ShortHashSet.java new file mode 100755 index 00000000..f2f35006 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortHashSet.java @@ -0,0 +1,787 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash set of shorts, implemented using open addressing with linear probing for + * collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeHashSet.java") +public class ShortHashSet extends AbstractShortCollection + implements ShortLookupContainer, ShortSet, Preallocable, Cloneable, Accountable { + /** The hash array holding keys. */ + public short[] keys; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any. + * + * @see #size() + * @see #hasEmptyKey + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** + * New instance with sane defaults. + * + * @see #ShortHashSet(int, double) + */ + public ShortHashSet() { + this(DEFAULT_EXPECTED_ELEMENTS, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with sane defaults. + * + * @see #ShortHashSet(int, double) + */ + public ShortHashSet(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ShortHashSet(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** New instance copying elements from another {@link ShortContainer}. */ + public ShortHashSet(ShortContainer container) { + this(container.size()); + addAll(container); + } + + /** {@inheritDoc} */ + @Override + public boolean add(short key) { + if (((key) == 0)) { + assert ((keys[mask + 1]) == 0); + boolean added = !hasEmptyKey; + hasEmptyKey = true; + return added; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return false; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key); + } else { + keys[slot] = key; + } + + assigned++; + return true; + } + } + + /** + * Adds all elements from the given list (vararg) to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + */ + public final int addAll(short... elements) { + ensureCapacity(elements.length); + int count = 0; + for (short e : elements) { + if (add(e)) { + count++; + } + } + return count; + } + + /** + * Adds all elements from the given {@link ShortContainer} to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + */ + public int addAll(ShortContainer container) { + ensureCapacity(container.size()); + return addAll((Iterable) container); + } + + /** + * Adds all elements from the given iterable to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + */ + public int addAll(Iterable iterable) { + int count = 0; + for (ShortCursor cursor : iterable) { + if (add(cursor.value)) { + count++; + } + } + return count; + } + + /** {@inheritDoc} */ + @Override + public short[] toArray() { + + final short[] cloned = (new short[size()]); + int j = 0; + if (hasEmptyKey) { + cloned[j++] = ((short) 0); + } + + final short[] keys = this.keys; + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + short existing; + if (!((existing = keys[slot]) == 0)) { + cloned[j++] = existing; + } + } + + return cloned; + } + + /** An alias for the (preferred) {@link #removeAll}. */ + public boolean remove(short key) { + if (((key) == 0)) { + boolean hadEmptyKey = hasEmptyKey; + hasEmptyKey = false; + return hadEmptyKey; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + shiftConflictingKeys(slot); + return true; + } + slot = (slot + 1) & mask; + } + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(short key) { + return remove(key) ? 1 : 0; + } + + /** + * Removes all keys present in a given container. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortContainer other) { + final int before = size(); + + // Try to iterate over the smaller set or over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof ShortLookupContainer) { + if (hasEmptyKey && other.contains(((short) 0))) { + hasEmptyKey = false; + } + + final short[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + short existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (ShortCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortPredicate predicate) { + int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(((short) 0))) { + hasEmptyKey = false; + } + } + + final short[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + short existing; + if (!((existing = keys[slot]) == 0)) { + if (predicate.apply(existing)) { + shiftConflictingKeys(slot); + continue; // Repeat the check for the same slot i (shifted). + } + } + slot++; + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public boolean contains(short key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + return false; + } + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + Arrays.fill(keys, ((short) 0)); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + keys = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public boolean isEmpty() { + return size() == 0; + } + + /** + * Ensure this container can hold at least the given number of elements without resizing its + * buffers. + * + * @param expectedElements The total number of elements, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final short[] prevKeys = this.keys; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys); + } + } + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + final short[] keys = this.keys; + for (int slot = mask; slot >= 0; slot--) { + short existing; + if (!((existing = keys[slot]) == 0)) { + h += BitMixer.mix(existing); + } + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && sameKeys(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + private boolean sameKeys(ShortSet other) { + if (other.size() != size()) { + return false; + } + + for (ShortCursor c : other) { + if (!contains(c.value)) { + return false; + } + } + + return true; + } + + /** {@inheritDoc} */ + @Override + public ShortHashSet clone() { + try { + + ShortHashSet cloned = (ShortHashSet) super.clone(); + cloned.keys = keys.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + @Override + public long ramBytesAllocated() { + // int: assigned, mask, keyMixer, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys); + } + + @Override + public long ramBytesUsed() { + // int: assigned, mask, keyMixer, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + protected final class EntryIterator extends AbstractIterator { + private final ShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new ShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortCursor fetch() { + final int mask = ShortHashSet.this.mask; + while (index <= mask) { + short existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = ((short) 0); + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + if (hasEmptyKey) { + procedure.apply(((short) 0)); + } + + final short[] keys = this.keys; + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + short existing; + if (!((existing = keys[slot]) == 0)) { + procedure.apply(existing); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + if (hasEmptyKey) { + if (!predicate.apply(((short) 0))) { + return predicate; + } + } + + final short[] keys = this.keys; + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + short existing; + if (!((existing = keys[slot]) == 0)) { + if (!predicate.apply(existing)) { + break; + } + } + } + + return predicate; + } + + /** + * Create a set from a variable number of arguments or an array of short. The + * elements are copied from the argument to the internal buffer. + */ + public static ShortHashSet from(short... elements) { + final ShortHashSet set = new ShortHashSet(elements.length); + set.addAll(elements); + return set; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(short key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up logic in + * certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between modifications (it will not be affected by read-only + * operations). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the set. + * @return A non-negative value of the logical "index" of the key in the set or a negative value + * if the key did not exist. + */ + public int indexOf(short key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index) { + assert index < 0 || index <= mask || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** + * Returns the exact value of the existing key. This method makes sense for sets of objects which + * define custom key-equality relationship. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the equivalent key currently stored in the set. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public short indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return keys[index]; + } + + /** + * Replaces the existing equivalent key with the given one and returns any previous value stored + * for that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @param equivalentKey The key to put in the set as a replacement. Must be equivalent to the key + * currently stored at the provided index. + * @return Returns the previous key stored in the set. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public short indexReplace(int index, short equivalentKey) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + assert ((keys[index]) == (equivalentKey)); + + short previousValue = keys[index]; + keys[index] = equivalentKey; + return previousValue; + } + + /** + * Inserts a key for an index that is not present in the set. This method may help in avoiding + * double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public void indexInsert(int index, short key) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + assert ((keys[index]) == 0); + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key); + } else { + keys[index] = key; + } + + assigned++; + } + } + + /** + * Removes a key at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public void indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + if (index > mask) { + hasEmptyKey = false; + } else { + shiftConflictingKeys(index); + } + } + + @Override + public String visualizeKeyDistribution(int characters) { + return ShortBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(short[] fromKeys) { + assert HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored keys into the new buffers. + final short[] keys = this.keys; + final int mask = this.mask; + short existing; + for (int i = fromKeys.length - 1; --i >= 0; ) { + if (!((existing = fromKeys[i]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + short[] prevKeys = this.keys; + try { + int emptyElementSlot = 1; + this.keys = (new short[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.keys == null ? 0 : size(), arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key to be inserted into the buffer but there is not + * enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, short pendingKey) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final short[] prevKeys = this.keys; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + + // Rehash old keys, including the pending key. + rehash(prevKeys); + } + + /** Shift all the slot-conflicting keys allocated to (and including) slot. */ + protected void shiftConflictingKeys(int gapSlot) { + final short[] keys = this.keys; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final short existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = ((short) 0); + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortIndexedContainer.java b/src/main/java/com/carrotsearch/hppc/ShortIndexedContainer.java new file mode 100755 index 00000000..fc7a41cf --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortIndexedContainer.java @@ -0,0 +1,91 @@ +package com.carrotsearch.hppc; + +import java.util.RandomAccess; + +/** + * An indexed container provides random access to elements based on an index. Indexes + * are zero-based. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeIndexedContainer.java") +public interface ShortIndexedContainer extends ShortCollection, RandomAccess { + /** + * Removes the first element that equals e1, returning whether an element has been + * removed. + */ + public boolean removeElement(short e1); + + /** + * Removes the first element that equals e1, returning its deleted position or + * -1 if the element was not found. + */ + public int removeFirst(short e1); + + /** + * Removes the last element that equals e1, returning its deleted position or + * -1 if the element was not found. + */ + public int removeLast(short e1); + + /** + * Returns the index of the first occurrence of the specified element in this list, or -1 if this + * list does not contain the element. + */ + public int indexOf(short e1); + + /** + * Returns the index of the last occurrence of the specified element in this list, or -1 if this + * list does not contain the element. + */ + public int lastIndexOf(short e1); + + /** Adds an element to the end of this container (the last index is incremented by one). */ + public void add(short e1); + + /** + * Inserts the specified element at the specified position in this list. + * + * @param index The index at which the element should be inserted, shifting any existing and + * subsequent elements to the right. + */ + public void insert(int index, short e1); + + /** + * Replaces the element at the specified position in this list with the specified element. + * + * @return Returns the previous value in the list. + */ + public short set(int index, short e1); + + /** + * @return Returns the element at index index from the list. + */ + public short get(int index); + + /** + * Removes the element at the specified position in this container and returns it. + * + * @see #removeFirst + * @see #removeLast + * @see #removeAll + */ + public short removeAt(int index); + + /** Removes and returns the last element of this container. This container must not be empty. */ + public short removeLast(); + + /** + * Removes from this container all of the elements with indexes between fromIndex, + * inclusive, and toIndex, exclusive. + */ + public void removeRange(int fromIndex, int toIndex); + + /** Returns this container elements as a stream. */ + + /** Sorts the elements in this container and returns this container. */ + public ShortIndexedContainer sort(); + + /** Reverses the elements in this container and returns this container. */ + public ShortIndexedContainer reverse(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortIntAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ShortIntAssociativeContainer.java new file mode 100755 index 00000000..07b4a19b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortIntAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see ShortContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface ShortIntAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(short key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortIntPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ShortIntProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ShortIntPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public ShortCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public IntContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortIntHashMap.java b/src/main/java/com/carrotsearch/hppc/ShortIntHashMap.java new file mode 100755 index 00000000..07bea9e2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortIntHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of short to int, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class ShortIntHashMap implements ShortIntMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public short[] keys; + + /** The array holding values. */ + public int[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public ShortIntHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ShortIntHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ShortIntHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ShortIntHashMap(ShortIntAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public int put(short key, int value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + int previousValue = hasEmptyKey ? values[mask + 1] : 0; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final int previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(ShortIntAssociativeContainer container) { + final int count = size(); + for (ShortIntCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (ShortIntCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public int putOrAdd(short key, int putValue, int incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((int) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public int addTo(short key, int incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public int remove(short key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return 0; + } + hasEmptyKey = false; + int previousValue = values[mask + 1]; + values[mask + 1] = 0; + return previousValue; + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final int previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof ShortLookupContainer) { + if (hasEmptyKey && other.contains(((short) 0))) { + hasEmptyKey = false; + values[mask + 1] = 0; + } + + final short[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + short existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (ShortCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortIntPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(((short) 0), values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0; + } + } + + final short[] keys = this.keys; + final int[] values = this.values; + for (int slot = 0; slot <= mask; ) { + short existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(((short) 0))) { + hasEmptyKey = false; + values[mask + 1] = 0; + } + } + + final short[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + short existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int get(short key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : 0; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0; + } + } + + /** {@inheritDoc} */ + @Override + public int getOrDefault(short key, int defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(short key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(short key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public int indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public int indexReplace(int index, int newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + int previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, short key, int value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public int indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + int previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, ((short) 0)); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (ShortIntCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(ShortIntHashMap other) { + if (other.size() != size()) { + return false; + } + + for (ShortIntCursor c : other) { + short key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final short[] prevKeys = this.keys; + final int[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final ShortIntCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new ShortIntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortIntCursor fetch() { + final int mask = ShortIntHashMap.this.mask; + while (index <= mask) { + short existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = ((short) 0); + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final short[] keys = this.keys; + final int[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(((short) 0), values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final short[] keys = this.keys; + final int[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(((short) 0), values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractShortCollection implements ShortLookupContainer { + private final ShortIntHashMap owner = ShortIntHashMap.this; + + @Override + public boolean contains(short e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((ShortIntProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((ShortIntPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final short e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final ShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new ShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortCursor fetch() { + final int mask = ShortIntHashMap.this.mask; + while (index <= mask) { + short existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = ((short) 0); + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public IntCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractIntCollection { + private final ShortIntHashMap owner = ShortIntHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(int value) { + for (ShortIntCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (ShortIntCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (ShortIntCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final int e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final IntPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final IntCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new IntCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected IntCursor fetch() { + final int mask = ShortIntHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public ShortIntHashMap clone() { + try { + + ShortIntHashMap cloned = (ShortIntHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (ShortIntCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return ShortBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ShortIntHashMap from(short[] keys, int[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ShortIntHashMap map = new ShortIntHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(short key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(short[] fromKeys, int[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final short[] keys = this.keys; + final int[] values = this.values; + final int mask = this.mask; + short existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + short[] prevKeys = this.keys; + int[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new short[arraySize + emptyElementSlot]); + this.values = (new int[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, short pendingKey, int pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final short[] prevKeys = this.keys; + final int[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final short[] keys = this.keys; + final int[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final short existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = ((short) 0); + values[gapSlot] = 0; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortIntMap.java b/src/main/java/com/carrotsearch/hppc/ShortIntMap.java new file mode 100755 index 00000000..78f19f42 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortIntMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ShortIntCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface ShortIntMap extends ShortIntAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public int get(short key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public int getOrDefault(short key, int defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public int put(short key, int value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(short key, int value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(ShortIntAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public int putOrAdd(short key, int putValue, int incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public int addTo(short key, int additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public int remove(short key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link ShortIntMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(short key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public int indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public int indexReplace(int index, int newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, short key, int value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public int indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortLongAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ShortLongAssociativeContainer.java new file mode 100755 index 00000000..32375150 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortLongAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see ShortContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface ShortLongAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(short key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortLongPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ShortLongProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ShortLongPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public ShortCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public LongContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortLongHashMap.java b/src/main/java/com/carrotsearch/hppc/ShortLongHashMap.java new file mode 100755 index 00000000..2fe676e5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortLongHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of short to long, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class ShortLongHashMap implements ShortLongMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public short[] keys; + + /** The array holding values. */ + public long[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public ShortLongHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ShortLongHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ShortLongHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ShortLongHashMap(ShortLongAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public long put(short key, long value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + long previousValue = hasEmptyKey ? values[mask + 1] : 0L; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final long previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return 0L; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(ShortLongAssociativeContainer container) { + final int count = size(); + for (ShortLongCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (ShortLongCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public long putOrAdd(short key, long putValue, long incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((long) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public long addTo(short key, long incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public long remove(short key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return 0L; + } + hasEmptyKey = false; + long previousValue = values[mask + 1]; + values[mask + 1] = 0L; + return previousValue; + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final long previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return 0L; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof ShortLookupContainer) { + if (hasEmptyKey && other.contains(((short) 0))) { + hasEmptyKey = false; + values[mask + 1] = 0L; + } + + final short[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + short existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (ShortCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortLongPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(((short) 0), values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = 0L; + } + } + + final short[] keys = this.keys; + final long[] values = this.values; + for (int slot = 0; slot <= mask; ) { + short existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(((short) 0))) { + hasEmptyKey = false; + values[mask + 1] = 0L; + } + } + + final short[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + short existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public long get(short key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : 0L; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return 0L; + } + } + + /** {@inheritDoc} */ + @Override + public long getOrDefault(short key, long defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(short key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(short key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public long indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public long indexReplace(int index, long newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + long previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, short key, long value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public long indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + long previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = 0L; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, ((short) 0)); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (ShortLongCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(ShortLongHashMap other) { + if (other.size() != size()) { + return false; + } + + for (ShortLongCursor c : other) { + short key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final short[] prevKeys = this.keys; + final long[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final ShortLongCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new ShortLongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortLongCursor fetch() { + final int mask = ShortLongHashMap.this.mask; + while (index <= mask) { + short existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = ((short) 0); + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final short[] keys = this.keys; + final long[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(((short) 0), values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final short[] keys = this.keys; + final long[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(((short) 0), values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractShortCollection implements ShortLookupContainer { + private final ShortLongHashMap owner = ShortLongHashMap.this; + + @Override + public boolean contains(short e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((ShortLongProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((ShortLongPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final short e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final ShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new ShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortCursor fetch() { + final int mask = ShortLongHashMap.this.mask; + while (index <= mask) { + short existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = ((short) 0); + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public LongCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractLongCollection { + private final ShortLongHashMap owner = ShortLongHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(long value) { + for (ShortLongCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (ShortLongCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (ShortLongCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final long e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final LongPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final LongCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new LongCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected LongCursor fetch() { + final int mask = ShortLongHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public ShortLongHashMap clone() { + try { + + ShortLongHashMap cloned = (ShortLongHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (ShortLongCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return ShortBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ShortLongHashMap from(short[] keys, long[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ShortLongHashMap map = new ShortLongHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(short key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(short[] fromKeys, long[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final short[] keys = this.keys; + final long[] values = this.values; + final int mask = this.mask; + short existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + short[] prevKeys = this.keys; + long[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new short[arraySize + emptyElementSlot]); + this.values = (new long[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, short pendingKey, long pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final short[] prevKeys = this.keys; + final long[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final short[] keys = this.keys; + final long[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final short existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = ((short) 0); + values[gapSlot] = 0L; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortLongMap.java b/src/main/java/com/carrotsearch/hppc/ShortLongMap.java new file mode 100755 index 00000000..682a924f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortLongMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ShortLongCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface ShortLongMap extends ShortLongAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public long get(short key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public long getOrDefault(short key, long defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public long put(short key, long value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(short key, long value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(ShortLongAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public long putOrAdd(short key, long putValue, long incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public long addTo(short key, long additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public long remove(short key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link ShortLongMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(short key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public long indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public long indexReplace(int index, long newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, short key, long value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public long indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortLookupContainer.java b/src/main/java/com/carrotsearch/hppc/ShortLookupContainer.java new file mode 100755 index 00000000..c049ef8f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortLookupContainer.java @@ -0,0 +1,12 @@ +package com.carrotsearch.hppc; + +/** + * Marker interface for containers that can check if they contain a given object in at least time + * O(log n) and ideally in amortized constant time O(1). + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeLookupContainer.java") +public interface ShortLookupContainer extends ShortContainer { + public boolean contains(short e); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortObjectAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ShortObjectAssociativeContainer.java new file mode 100755 index 00000000..0c3b670b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortObjectAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see ShortContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface ShortObjectAssociativeContainer extends Iterable> { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator> iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(short key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortObjectPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ShortObjectProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public > T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ShortObjectPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public > T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public ShortCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public ObjectContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/ShortObjectHashMap.java new file mode 100755 index 00000000..6b8a20b0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortObjectHashMap.java @@ -0,0 +1,1050 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of short to Object, implemented using open addressing with + * linear probing for collision resolution. Supports null values. + * + * @see HPPC interfaces diagram + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class ShortObjectHashMap + implements ShortObjectMap, Preallocable, Cloneable, Accountable { + /** The array holding keys. */ + public short[] keys; + + /** The array holding values. */ + public Object[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public ShortObjectHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ShortObjectHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ShortObjectHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ShortObjectHashMap(ShortObjectAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public VType put(short key, VType value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + VType previousValue = hasEmptyKey ? (VType) values[mask + 1] : null; + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final VType previousValue = (VType) values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return null; + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(ShortObjectAssociativeContainer container) { + final int count = size(); + for (ShortObjectCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable> iterable) { + final int count = size(); + for (ShortObjectCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** {@inheritDoc} */ + @Override + public VType remove(short key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return null; + } + hasEmptyKey = false; + VType previousValue = (VType) values[mask + 1]; + values[mask + 1] = null; + return previousValue; + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final VType previousValue = (VType) values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return null; + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof ShortLookupContainer) { + if (hasEmptyKey && other.contains(((short) 0))) { + hasEmptyKey = false; + values[mask + 1] = null; + } + + final short[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + short existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (ShortCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortObjectPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(((short) 0), (VType) values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = null; + } + } + + final short[] keys = this.keys; + final VType[] values = (VType[]) this.values; + for (int slot = 0; slot <= mask; ) { + short existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(((short) 0))) { + hasEmptyKey = false; + values[mask + 1] = null; + } + } + + final short[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + short existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public VType get(short key) { + if (((key) == 0)) { + return hasEmptyKey ? (VType) values[mask + 1] : null; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return (VType) values[slot]; + } + slot = (slot + 1) & mask; + } + + return null; + } + } + + /** {@inheritDoc} */ + @Override + public VType getOrDefault(short key, VType defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? (VType) values[mask + 1] : defaultValue; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return (VType) values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(short key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(short key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public VType indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return (VType) values[index]; + } + + /** {@inheritDoc} */ + @Override + public VType indexReplace(int index, VType newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + VType previousValue = (VType) values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, short key, VType value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public VType indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + VType previousValue = (VType) values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = null; + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, ((short) 0)); + + Arrays.fill(values, null); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (ShortObjectCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** + * Return true if all keys of some other container exist in this container. Values are compared + * using {@link Objects#equals(Object)} method. + */ + protected boolean equalElements(ShortObjectHashMap other) { + if (other.size() != size()) { + return false; + } + + for (ShortObjectCursor c : other) { + short key = c.key; + if (!containsKey(key) || !java.util.Objects.equals(c.value, get(key))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final short[] prevKeys = this.keys; + final VType[] prevValues = (VType[]) this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final ShortObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new ShortObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortObjectCursor fetch() { + final int mask = ShortObjectHashMap.this.mask; + while (index <= mask) { + short existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = (VType) values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = ((short) 0); + cursor.value = (VType) values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator> iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T procedure) { + final short[] keys = this.keys; + final VType[] values = (VType[]) this.values; + + if (hasEmptyKey) { + procedure.apply(((short) 0), (VType) values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public > T forEach(T predicate) { + final short[] keys = this.keys; + final VType[] values = (VType[]) this.values; + + if (hasEmptyKey) { + if (!predicate.apply(((short) 0), (VType) values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractShortCollection implements ShortLookupContainer { + private final ShortObjectHashMap owner = ShortObjectHashMap.this; + + @Override + public boolean contains(short e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((ShortObjectProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((ShortObjectPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final short e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final ShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new ShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortCursor fetch() { + final int mask = ShortObjectHashMap.this.mask; + while (index <= mask) { + short existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = ((short) 0); + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public ObjectCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractObjectCollection { + private final ShortObjectHashMap owner = ShortObjectHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(VType value) { + for (ShortObjectCursor c : owner) { + if (java.util.Objects.equals(value, c.value)) { + return true; + } + } + return false; + } + + @Override + public > T forEach(T procedure) { + for (ShortObjectCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public > T forEach(T predicate) { + for (ShortObjectCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator> iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final VType e) { + return owner.removeAll((key, value) -> java.util.Objects.equals(e, value)); + } + + @Override + public int removeAll(final ObjectPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator> { + private final ObjectCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new ObjectCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ObjectCursor fetch() { + final int mask = ShortObjectHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = (VType) values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = (VType) values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public ShortObjectHashMap clone() { + try { + + ShortObjectHashMap cloned = (ShortObjectHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (ShortObjectCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return ShortBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ShortObjectHashMap from(short[] keys, VType[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ShortObjectHashMap map = new ShortObjectHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(short key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(short[] fromKeys, VType[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final short[] keys = this.keys; + final VType[] values = (VType[]) this.values; + final int mask = this.mask; + short existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + short[] prevKeys = this.keys; + VType[] prevValues = (VType[]) this.values; + try { + int emptyElementSlot = 1; + this.keys = (new short[arraySize + emptyElementSlot]); + this.values = ((VType[]) new Object[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, short pendingKey, VType pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final short[] prevKeys = this.keys; + final VType[] prevValues = (VType[]) this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final short[] keys = this.keys; + final VType[] values = (VType[]) this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final short existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = ((short) 0); + values[gapSlot] = null; + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortObjectMap.java b/src/main/java/com/carrotsearch/hppc/ShortObjectMap.java new file mode 100755 index 00000000..732c57e7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortObjectMap.java @@ -0,0 +1,181 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ShortObjectCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface ShortObjectMap extends ShortObjectAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public VType get(short key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public VType getOrDefault(short key, VType defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public VType put(short key, VType value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(short key, VType value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(ShortObjectAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable> iterable); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public VType remove(short key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link ShortObjectMap} and both objects contains exactly the + * same key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(short key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public VType indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public VType indexReplace(int index, VType newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, short key, VType value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public VType indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortSet.java b/src/main/java/com/carrotsearch/hppc/ShortSet.java new file mode 100755 index 00000000..f87250b4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortSet.java @@ -0,0 +1,33 @@ +package com.carrotsearch.hppc; + +/** A set of shorts. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeSet.java") +public interface ShortSet extends ShortCollection { + /** + * Adds k to the set. + * + * @return Returns true if this element was not part of the set before. Returns + * false if an equal element is already part of the set, does not replace the + * existing element with the argument. + */ + public boolean add(short k); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); + + /** + * Adds all elements from the given {@link ShortContainer} to this set. + * + * @return Returns the number of elements actually added as a result of this call (not previously + * present in the set). + * @since 0.9.1 + */ + public int addAll(ShortContainer container); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortShortAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ShortShortAssociativeContainer.java new file mode 100755 index 00000000..e1adb957 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortShortAssociativeContainer.java @@ -0,0 +1,105 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.Iterator; + +/** + * An associative container from keys to (one or possibly more) values. + * + * @see ShortContainer + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeAssociativeContainer.java") +public interface ShortShortAssociativeContainer extends Iterable { + /** + * Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as + * a cursor and it returns the same cursor instance on every call to {@link + * Iterator#next()}. To read the current key and value use the cursor's public fields. An example + * is shown below. + * + *

+   * for (IntShortCursor c : intShortMap) {
+   *   System.out.println("index=" + c.index + " key=" + c.key + " value=" + c.value);
+   * }
+ * + *

The index field inside the cursor gives the internal index inside the + * container's implementation. The interpretation of this index depends on to the container. + */ + @Override + public Iterator iterator(); + + /** + * Returns true if this container has an association to a value for the given key. + */ + public boolean containsKey(short key); + + /** + * @return Returns the current size (number of assigned keys) in the container. + */ + public int size(); + + /** + * @return Return true if this hash map contains no assigned keys. + */ + public boolean isEmpty(); + + /** + * Removes all keys (and associated values) present in a given container. An alias to: + * + *

+   * keys().removeAll(container)
+   * 
+ * + * but with no additional overhead. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortContainer container); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortPredicate predicate); + + /** + * Removes all keys (and associated values) for which the predicate returns true. + * + * @return Returns the number of elements actually removed as a result of this call. + */ + public int removeAll(ShortShortPredicate predicate); + + /** + * Applies a given procedure to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ShortShortProcedure}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + */ + public T forEach(T procedure); + + /** + * Applies a given predicate to all keys-value pairs in this container. Returns the argument (any + * subclass of {@link ShortShortPredicate}. This lets the caller call methods of the argument by + * chaining the call (even if the argument is an anonymous type) to retrieve computed values. + * + *

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public ShortCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public ShortContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortShortHashMap.java b/src/main/java/com/carrotsearch/hppc/ShortShortHashMap.java new file mode 100755 index 00000000..589b23c3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortShortHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of short to short, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class ShortShortHashMap implements ShortShortMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public short[] keys; + + /** The array holding values. */ + public short[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public ShortShortHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ShortShortHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public ShortShortHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public ShortShortHashMap(ShortShortAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public short put(short key, short value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + short previousValue = hasEmptyKey ? values[mask + 1] : ((short) 0); + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final short previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return ((short) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(ShortShortAssociativeContainer container) { + final int count = size(); + for (ShortShortCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (ShortShortCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public short putOrAdd(short key, short putValue, short incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((short) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public short addTo(short key, short incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public short remove(short key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return ((short) 0); + } + hasEmptyKey = false; + short previousValue = values[mask + 1]; + values[mask + 1] = ((short) 0); + return previousValue; + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final short previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return ((short) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof ShortLookupContainer) { + if (hasEmptyKey && other.contains(((short) 0))) { + hasEmptyKey = false; + values[mask + 1] = ((short) 0); + } + + final short[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + short existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (ShortCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortShortPredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(((short) 0), values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = ((short) 0); + } + } + + final short[] keys = this.keys; + final short[] values = this.values; + for (int slot = 0; slot <= mask; ) { + short existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(ShortPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(((short) 0))) { + hasEmptyKey = false; + values[mask + 1] = ((short) 0); + } + } + + final short[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + short existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public short get(short key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : ((short) 0); + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return ((short) 0); + } + } + + /** {@inheritDoc} */ + @Override + public short getOrDefault(short key, short defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(short key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final short[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(short key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final short[] keys = this.keys; + int slot = hashKey(key) & mask; + + short existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public short indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public short indexReplace(int index, short newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + short previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, short key, short value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public short indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + short previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = ((short) 0); + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, ((short) 0)); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (ShortShortCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(ShortShortHashMap other) { + if (other.size() != size()) { + return false; + } + + for (ShortShortCursor c : other) { + short key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final short[] prevKeys = this.keys; + final short[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final ShortShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new ShortShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortShortCursor fetch() { + final int mask = ShortShortHashMap.this.mask; + while (index <= mask) { + short existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = ((short) 0); + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final short[] keys = this.keys; + final short[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(((short) 0), values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final short[] keys = this.keys; + final short[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(((short) 0), values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractShortCollection implements ShortLookupContainer { + private final ShortShortHashMap owner = ShortShortHashMap.this; + + @Override + public boolean contains(short e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((ShortShortProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((ShortShortPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final short e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final ShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new ShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortCursor fetch() { + final int mask = ShortShortHashMap.this.mask; + while (index <= mask) { + short existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = ((short) 0); + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public ShortCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractShortCollection { + private final ShortShortHashMap owner = ShortShortHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(short value) { + for (ShortShortCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (ShortShortCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (ShortShortCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final short e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final ShortPredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ShortCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new ShortCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ShortCursor fetch() { + final int mask = ShortShortHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public ShortShortHashMap clone() { + try { + + ShortShortHashMap cloned = (ShortShortHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (ShortShortCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return ShortBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static ShortShortHashMap from(short[] keys, short[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + ShortShortHashMap map = new ShortShortHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *

The output from this function should evenly distribute keys across the entire integer range. + */ + protected int hashKey(short key) { + assert !((key) == 0); // Handled as a special case (empty slot marker). + return BitMixer.mixPhi(key); + } + + /** + * Validate load factor range and return it. Override and suppress if you need insane load + * factors. + */ + protected double verifyLoadFactor(double loadFactor) { + checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR); + return loadFactor; + } + + /** Rehash from old buffers to new buffers. */ + protected void rehash(short[] fromKeys, short[] fromValues) { + assert fromKeys.length == fromValues.length + && HashContainers.checkPowerOfTwo(fromKeys.length - 1); + + // Rehash all stored key/value pairs into the new buffers. + final short[] keys = this.keys; + final short[] values = this.values; + final int mask = this.mask; + short existing; + + // Copy the zero element's slot, then rehash everything else. + int from = fromKeys.length - 1; + keys[keys.length - 1] = fromKeys[from]; + values[values.length - 1] = fromValues[from]; + while (--from >= 0) { + if (!((existing = fromKeys[from]) == 0)) { + int slot = hashKey(existing) & mask; + while (!((keys[slot]) == 0)) { + slot = (slot + 1) & mask; + } + keys[slot] = existing; + values[slot] = fromValues[from]; + } + } + } + + /** + * Allocate new internal buffers. This method attempts to allocate and assign internal buffers + * atomically (either allocations succeed or not). + */ + protected void allocateBuffers(int arraySize) { + assert Integer.bitCount(arraySize) == 1; + + // Ensure no change is done if we hit an OOM. + short[] prevKeys = this.keys; + short[] prevValues = this.values; + try { + int emptyElementSlot = 1; + this.keys = (new short[arraySize + emptyElementSlot]); + this.values = (new short[arraySize + emptyElementSlot]); + } catch (OutOfMemoryError e) { + this.keys = prevKeys; + this.values = prevValues; + throw new BufferAllocationException( + "Not enough memory to allocate buffers for rehashing: %,d -> %,d", + e, this.mask + 1, arraySize); + } + + this.resizeAt = expandAtCount(arraySize, loadFactor); + this.mask = arraySize - 1; + } + + /** + * This method is invoked when there is a new key/ value pair to be inserted into the buffers but + * there is not enough empty slots to do so. + * + *

New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we + * assign the pending element to the previous buffer (possibly violating the invariant of having + * at least one empty slot) and rehash all keys, substituting new buffers at the end. + */ + protected void allocateThenInsertThenRehash(int slot, short pendingKey, short pendingValue) { + assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0); + + // Try to allocate new buffers first. If we OOM, we leave in a consistent state. + final short[] prevKeys = this.keys; + final short[] prevValues = this.values; + allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor)); + assert this.keys.length > prevKeys.length; + + // We have succeeded at allocating new data so insert the pending key/value at + // the free slot in the old arrays before rehashing. + prevKeys[slot] = pendingKey; + prevValues[slot] = pendingValue; + + // Rehash old keys, including the pending key. + rehash(prevKeys, prevValues); + } + + /** + * Shift all the slot-conflicting keys and values allocated to (and including) slot. + */ + protected void shiftConflictingKeys(int gapSlot) { + final short[] keys = this.keys; + final short[] values = this.values; + final int mask = this.mask; + + // Perform shifts of conflicting keys to fill in the gap. + int distance = 0; + while (true) { + final int slot = (gapSlot + (++distance)) & mask; + final short existing = keys[slot]; + if (((existing) == 0)) { + break; + } + + final int idealSlot = hashKey(existing); + final int shift = (slot - idealSlot) & mask; + if (shift >= distance) { + // Entry at this position was originally at or before the gap slot. + // Move the conflict-shifted entry to the gap's position and repeat the procedure + // for any entries to the right of the current position, treating it + // as the new gap. + keys[gapSlot] = existing; + values[gapSlot] = values[slot]; + gapSlot = slot; + distance = 0; + } + } + + // Mark the last found gap slot without a conflict as empty. + keys[gapSlot] = ((short) 0); + values[gapSlot] = ((short) 0); + assigned--; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortShortMap.java b/src/main/java/com/carrotsearch/hppc/ShortShortMap.java new file mode 100755 index 00000000..d90c602e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortShortMap.java @@ -0,0 +1,205 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ShortShortCursor; + +/** An associative container with unique binding from keys to a single value. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java") +public interface ShortShortMap extends ShortShortAssociativeContainer { + /** + * @return Returns the value associated with the given key or the default value for the value + * type, if the key is not associated with any value. For numeric value types, this default + * value is 0, for object types it is {@code null}. + */ + public short get(short key); + + /** + * @return Returns the value associated with the given key or the provided default value if the + * key is not associated with any value. + */ + public short getOrDefault(short key, short defaultValue); + + /** + * Place a given key and value in the container. + * + * @return The value previously stored under the given key in the map is returned. + */ + public short put(short key, short value); + + /** + * If the specified key is not already associated with a value, associates it with the given + * value. + * + * @return {@code true} if {@code key} did not exist and {@code value} was placed in the map, + * {@code false} otherwise. + */ + public default boolean putIfAbsent(short key, short value) { + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + return false; + } else { + indexInsert(keyIndex, key, value); + return true; + } + } + + /** + * Puts all keys from another container to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(ShortShortAssociativeContainer container); + + /** + * Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if + * such keys are present. + * + * @return Returns the number of keys added to the map as a result of this call (not previously + * present in the map). Values of existing keys are overwritten. + */ + public int putAll(Iterable iterable); + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public short putOrAdd(short key, short putValue, short incrementValue); + + /** + * An equivalent of calling + * + *

+   * putOrAdd(key, additionValue, additionValue);
+   * 
+ * + * @param key The key of the value to adjust. + * @param additionValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + public short addTo(short key, short additionValue); + + /** + * Remove all values at the given key. The default value for the key type is returned if the value + * does not exist in the map. + */ + public short remove(short key); + + /** + * Compares the specified object with this set for equality. Returns {@code true} if and only if + * the specified object is also a {@link ShortShortMap} and both objects contains exactly the same + * key-value pairs. + */ + public boolean equals(Object obj); + + /** + * @return A hash code of elements stored in the map. The hash code is defined as a sum of hash + * codes of keys and values stored within the set). Because sum is commutative, this ensures + * that different order of elements in a set does not affect the hash code. + */ + public int hashCode(); + + /** + * Returns a logical "index" of a given key that can be used to speed up follow-up value setters + * or getters in certain scenarios (conditional logic). + * + *

The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be) + * contiguous. + * + *

The index is valid only between map modifications (it will not be affected by read-only + * operations like iteration or value retrievals). + * + * @see #indexExists + * @see #indexGet + * @see #indexInsert + * @see #indexReplace + * @param key The key to locate in the map. + * @return A non-negative value of the logical "index" of the key in the map or a negative value + * if the key did not exist. + */ + public int indexOf(short key); + + /** + * @see #indexOf + * @param index The index of a given key, as returned from {@link #indexOf}. + * @return Returns true if the index corresponds to an existing key or false + * otherwise. This is equivalent to checking whether the index is a positive value (existing + * keys) or a negative value (non-existing keys). + */ + public boolean indexExists(int index); + + /** + * Returns the value associated with an existing key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the value currently associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public short indexGet(int index); + + /** + * Replaces the value associated with an existing key and returns any previous value stored for + * that key. + * + * @see #indexOf + * @param index The index of an existing key. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public short indexReplace(int index, short newValue); + + /** + * Inserts a key-value pair for a key that is not present in the map. This method may help in + * avoiding double recalculation of the key's hash. + * + * @see #indexOf + * @param index The index of a previously non-existing key, as returned from {@link #indexOf}. + * @throws AssertionError If assertions are enabled and the index corresponds to an existing key. + */ + public void indexInsert(int index, short key, short value); + + /** + * Removes a key-value pair at an index previously acquired from {@link #indexOf}. + * + * @see #indexOf + * @param index The index of the key to remove, as returned from {@link #indexOf}. + * @return Returns the previous value associated with the key. + * @throws AssertionError If assertions are enabled and the index does not correspond to an + * existing key. + */ + public short indexRemove(int index); + + /** + * Clear all keys and values in the container. + * + * @see #release() + */ + public void clear(); + + /** + * Removes all elements from the collection and additionally releases any internal buffers. + * Typically, if the object is to be reused, a simple {@link #clear()} should be a better + * alternative since it'll avoid reallocation. + * + * @see #clear() + */ + public void release(); + + /** + * Visually depict the distribution of keys. + * + * @param characters The number of characters to "squeeze" the entire buffer into. + * @return Returns a sequence of characters where '.' depicts an empty fragment of the internal + * buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything + * between 1 and 9 is between. + */ + public String visualizeKeyDistribution(int characters); +} diff --git a/src/main/java/com/carrotsearch/hppc/ShortStack.java b/src/main/java/com/carrotsearch/hppc/ShortStack.java new file mode 100755 index 00000000..2c972c32 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortStack.java @@ -0,0 +1,137 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.cursors.ShortCursor; + +/** + * A subclass of {@link ShortArrayList} adding stack-related utility methods. The top of the stack + * is at the {@link #size()} - 1 element. + */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java") +public class ShortStack extends ShortArrayList { + /** New instance with sane defaults. */ + public ShortStack() { + super(); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public ShortStack(int expectedElements) { + super(expectedElements); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + * @param resizer Underlying buffer sizing strategy. + */ + public ShortStack(int expectedElements, ArraySizingStrategy resizer) { + super(expectedElements, resizer); + } + + /** Create a stack by pushing all elements of another container to it. */ + public ShortStack(ShortContainer container) { + super(container); + } + + /** Adds one short to the stack. */ + public void push(short e1) { + ensureBufferSpace(1); + buffer[elementsCount++] = e1; + } + + /** Adds two shorts to the stack. */ + public void push(short e1, short e2) { + ensureBufferSpace(2); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + } + + /** Adds three shorts to the stack. */ + public void push(short e1, short e2, short e3) { + ensureBufferSpace(3); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + buffer[elementsCount++] = e3; + } + + /** Adds four shorts to the stack. */ + public void push(short e1, short e2, short e3, short e4) { + ensureBufferSpace(4); + buffer[elementsCount++] = e1; + buffer[elementsCount++] = e2; + buffer[elementsCount++] = e3; + buffer[elementsCount++] = e4; + } + + /** Add a range of array elements to the stack. */ + public void push(short[] elements, int start, int len) { + assert start >= 0 && len >= 0; + + ensureBufferSpace(len); + System.arraycopy(elements, start, buffer, elementsCount, len); + elementsCount += len; + } + + /** + * Vararg-signature method for pushing elements at the top of the stack. + * + *

This method is handy, but costly if used in tight loops (anonymous array passing) + */ + public final void push(short... elements) { + push(elements, 0, elements.length); + } + + /** Pushes all elements from another container to the top of the stack. */ + public int pushAll(ShortContainer container) { + return addAll(container); + } + + /** Pushes all elements from another iterable to the top of the stack. */ + public int pushAll(Iterable iterable) { + return addAll(iterable); + } + + /** Discard an arbitrary number of elements from the top of the stack. */ + public void discard(int count) { + assert elementsCount >= count; + + elementsCount -= count; + } + + /** Discard the top element from the stack. */ + public void discard() { + assert elementsCount > 0; + + elementsCount--; + } + + /** Remove the top element from the stack and return it. */ + public short pop() { + return removeLast(); + } + + /** Peek at the top element on the stack. */ + public short peek() { + assert elementsCount > 0; + return buffer[elementsCount - 1]; + } + + /** Create a stack by pushing a variable number of arguments to it. */ + public static ShortStack from(short... elements) { + final ShortStack stack = new ShortStack(elements.length); + stack.push(elements); + return stack; + } + + /** {@inheritDoc} */ + @Override + public ShortStack clone() { + return (ShortStack) super.clone(); + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationCharByteHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationCharByteHashMap.java new file mode 100755 index 00000000..4e0da79c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationCharByteHashMap.java @@ -0,0 +1,440 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link CharByteHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link CharByteHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationCharByteHashMap implements CharByteMap { + public final CharByteHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationCharByteHashMap(CharByteHashMap delegate, CharComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationCharByteHashMap(CharByteHashMap delegate, CharByteComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final char[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, CharComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + char[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, CharByteComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final char[] keys = delegate.keys; + final byte[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(char key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(CharContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(CharBytePredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final char[] keys = delegate.keys; + final byte[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final char[] keys = delegate.keys; + final byte[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public CharCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public ByteContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public byte get(char key) { + return delegate.get(key); + } + + @Override + public byte getOrDefault(char key, byte defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public byte put(char key, byte value) { + throw readOnlyException(); + } + + @Override + public int putAll(CharByteAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public byte putOrAdd(char key, byte putValue, byte incrementValue) { + throw readOnlyException(); + } + + @Override + public byte addTo(char key, byte additionValue) { + throw readOnlyException(); + } + + @Override + public byte remove(char key) { + throw readOnlyException(); + } + + @Override + public int indexOf(char key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public byte indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public byte indexReplace(int index, byte newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, char key, byte value) { + throw readOnlyException(); + } + + @Override + public byte indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final CharByteCursor cursor = new CharByteCursor(); + private int index; + + @Override + protected CharByteCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { + private final SortedIterationCharByteHashMap owner = SortedIterationCharByteHashMap.this; + + @Override + public boolean contains(char e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((CharByteProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((CharBytePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final char e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final CharCursor cursor = new CharCursor(); + private int index; + + @Override + protected CharCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractByteCollection { + private final SortedIterationCharByteHashMap owner = SortedIterationCharByteHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(byte value) { + for (CharByteCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((CharByteProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((CharBytePredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final byte e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final BytePredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ByteCursor cursor = new ByteCursor(); + private int index; + + @Override + protected ByteCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationCharCharHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationCharCharHashMap.java new file mode 100755 index 00000000..e5f5017d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationCharCharHashMap.java @@ -0,0 +1,440 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link CharCharHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link CharCharHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationCharCharHashMap implements CharCharMap { + public final CharCharHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationCharCharHashMap(CharCharHashMap delegate, CharComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationCharCharHashMap(CharCharHashMap delegate, CharCharComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final char[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, CharComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + char[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, CharCharComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final char[] keys = delegate.keys; + final char[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(char key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(CharContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(CharCharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final char[] keys = delegate.keys; + final char[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final char[] keys = delegate.keys; + final char[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public CharCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public CharContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public char get(char key) { + return delegate.get(key); + } + + @Override + public char getOrDefault(char key, char defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public char put(char key, char value) { + throw readOnlyException(); + } + + @Override + public int putAll(CharCharAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public char putOrAdd(char key, char putValue, char incrementValue) { + throw readOnlyException(); + } + + @Override + public char addTo(char key, char additionValue) { + throw readOnlyException(); + } + + @Override + public char remove(char key) { + throw readOnlyException(); + } + + @Override + public int indexOf(char key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public char indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public char indexReplace(int index, char newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, char key, char value) { + throw readOnlyException(); + } + + @Override + public char indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final CharCharCursor cursor = new CharCharCursor(); + private int index; + + @Override + protected CharCharCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { + private final SortedIterationCharCharHashMap owner = SortedIterationCharCharHashMap.this; + + @Override + public boolean contains(char e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((CharCharProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((CharCharPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final char e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final CharCursor cursor = new CharCursor(); + private int index; + + @Override + protected CharCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractCharCollection { + private final SortedIterationCharCharHashMap owner = SortedIterationCharCharHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(char value) { + for (CharCharCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((CharCharProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((CharCharPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final char e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final CharCursor cursor = new CharCursor(); + private int index; + + @Override + protected CharCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationCharDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationCharDoubleHashMap.java new file mode 100755 index 00000000..0d54399c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationCharDoubleHashMap.java @@ -0,0 +1,441 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link CharDoubleHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link CharDoubleHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationCharDoubleHashMap implements CharDoubleMap { + public final CharDoubleHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationCharDoubleHashMap(CharDoubleHashMap delegate, CharComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationCharDoubleHashMap( + CharDoubleHashMap delegate, CharDoubleComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final char[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, CharComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + char[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, CharDoubleComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final char[] keys = delegate.keys; + final double[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(char key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(CharContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(CharDoublePredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final char[] keys = delegate.keys; + final double[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final char[] keys = delegate.keys; + final double[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public CharCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public DoubleContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public double get(char key) { + return delegate.get(key); + } + + @Override + public double getOrDefault(char key, double defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public double put(char key, double value) { + throw readOnlyException(); + } + + @Override + public int putAll(CharDoubleAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public double putOrAdd(char key, double putValue, double incrementValue) { + throw readOnlyException(); + } + + @Override + public double addTo(char key, double additionValue) { + throw readOnlyException(); + } + + @Override + public double remove(char key) { + throw readOnlyException(); + } + + @Override + public int indexOf(char key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public double indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public double indexReplace(int index, double newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, char key, double value) { + throw readOnlyException(); + } + + @Override + public double indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final CharDoubleCursor cursor = new CharDoubleCursor(); + private int index; + + @Override + protected CharDoubleCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { + private final SortedIterationCharDoubleHashMap owner = SortedIterationCharDoubleHashMap.this; + + @Override + public boolean contains(char e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((CharDoubleProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((CharDoublePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final char e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final CharCursor cursor = new CharCursor(); + private int index; + + @Override + protected CharCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractDoubleCollection { + private final SortedIterationCharDoubleHashMap owner = SortedIterationCharDoubleHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(double value) { + for (CharDoubleCursor c : owner) { + if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((CharDoubleProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((CharDoublePredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final double e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final DoublePredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final DoubleCursor cursor = new DoubleCursor(); + private int index; + + @Override + protected DoubleCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationCharFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationCharFloatHashMap.java new file mode 100755 index 00000000..90c227ef --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationCharFloatHashMap.java @@ -0,0 +1,441 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link CharFloatHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link CharFloatHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationCharFloatHashMap implements CharFloatMap { + public final CharFloatHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationCharFloatHashMap(CharFloatHashMap delegate, CharComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationCharFloatHashMap( + CharFloatHashMap delegate, CharFloatComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final char[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, CharComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + char[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, CharFloatComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final char[] keys = delegate.keys; + final float[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(char key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(CharContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(CharFloatPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final char[] keys = delegate.keys; + final float[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final char[] keys = delegate.keys; + final float[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public CharCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public FloatContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public float get(char key) { + return delegate.get(key); + } + + @Override + public float getOrDefault(char key, float defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public float put(char key, float value) { + throw readOnlyException(); + } + + @Override + public int putAll(CharFloatAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public float putOrAdd(char key, float putValue, float incrementValue) { + throw readOnlyException(); + } + + @Override + public float addTo(char key, float additionValue) { + throw readOnlyException(); + } + + @Override + public float remove(char key) { + throw readOnlyException(); + } + + @Override + public int indexOf(char key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public float indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public float indexReplace(int index, float newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, char key, float value) { + throw readOnlyException(); + } + + @Override + public float indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final CharFloatCursor cursor = new CharFloatCursor(); + private int index; + + @Override + protected CharFloatCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { + private final SortedIterationCharFloatHashMap owner = SortedIterationCharFloatHashMap.this; + + @Override + public boolean contains(char e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((CharFloatProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((CharFloatPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final char e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final CharCursor cursor = new CharCursor(); + private int index; + + @Override + protected CharCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractFloatCollection { + private final SortedIterationCharFloatHashMap owner = SortedIterationCharFloatHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(float value) { + for (CharFloatCursor c : owner) { + if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((CharFloatProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((CharFloatPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final float e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final FloatPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final FloatCursor cursor = new FloatCursor(); + private int index; + + @Override + protected FloatCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationCharIntHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationCharIntHashMap.java new file mode 100755 index 00000000..dde200f4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationCharIntHashMap.java @@ -0,0 +1,440 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link CharIntHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link CharIntHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationCharIntHashMap implements CharIntMap { + public final CharIntHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationCharIntHashMap(CharIntHashMap delegate, CharComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationCharIntHashMap(CharIntHashMap delegate, CharIntComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final char[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, CharComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + char[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, CharIntComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final char[] keys = delegate.keys; + final int[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(char key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(CharContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(CharIntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final char[] keys = delegate.keys; + final int[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final char[] keys = delegate.keys; + final int[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public CharCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public IntContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public int get(char key) { + return delegate.get(key); + } + + @Override + public int getOrDefault(char key, int defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public int put(char key, int value) { + throw readOnlyException(); + } + + @Override + public int putAll(CharIntAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public int putOrAdd(char key, int putValue, int incrementValue) { + throw readOnlyException(); + } + + @Override + public int addTo(char key, int additionValue) { + throw readOnlyException(); + } + + @Override + public int remove(char key) { + throw readOnlyException(); + } + + @Override + public int indexOf(char key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public int indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public int indexReplace(int index, int newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, char key, int value) { + throw readOnlyException(); + } + + @Override + public int indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final CharIntCursor cursor = new CharIntCursor(); + private int index; + + @Override + protected CharIntCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { + private final SortedIterationCharIntHashMap owner = SortedIterationCharIntHashMap.this; + + @Override + public boolean contains(char e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((CharIntProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((CharIntPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final char e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final CharCursor cursor = new CharCursor(); + private int index; + + @Override + protected CharCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractIntCollection { + private final SortedIterationCharIntHashMap owner = SortedIterationCharIntHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(int value) { + for (CharIntCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((CharIntProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((CharIntPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final int e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final IntCursor cursor = new IntCursor(); + private int index; + + @Override + protected IntCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationCharLongHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationCharLongHashMap.java new file mode 100755 index 00000000..76ec360d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationCharLongHashMap.java @@ -0,0 +1,440 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link CharLongHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link CharLongHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationCharLongHashMap implements CharLongMap { + public final CharLongHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationCharLongHashMap(CharLongHashMap delegate, CharComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationCharLongHashMap(CharLongHashMap delegate, CharLongComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final char[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, CharComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + char[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, CharLongComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final char[] keys = delegate.keys; + final long[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(char key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(CharContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(CharLongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final char[] keys = delegate.keys; + final long[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final char[] keys = delegate.keys; + final long[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public CharCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public LongContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public long get(char key) { + return delegate.get(key); + } + + @Override + public long getOrDefault(char key, long defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public long put(char key, long value) { + throw readOnlyException(); + } + + @Override + public int putAll(CharLongAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public long putOrAdd(char key, long putValue, long incrementValue) { + throw readOnlyException(); + } + + @Override + public long addTo(char key, long additionValue) { + throw readOnlyException(); + } + + @Override + public long remove(char key) { + throw readOnlyException(); + } + + @Override + public int indexOf(char key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public long indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public long indexReplace(int index, long newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, char key, long value) { + throw readOnlyException(); + } + + @Override + public long indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final CharLongCursor cursor = new CharLongCursor(); + private int index; + + @Override + protected CharLongCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { + private final SortedIterationCharLongHashMap owner = SortedIterationCharLongHashMap.this; + + @Override + public boolean contains(char e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((CharLongProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((CharLongPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final char e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final CharCursor cursor = new CharCursor(); + private int index; + + @Override + protected CharCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractLongCollection { + private final SortedIterationCharLongHashMap owner = SortedIterationCharLongHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(long value) { + for (CharLongCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((CharLongProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((CharLongPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final long e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final LongCursor cursor = new LongCursor(); + private int index; + + @Override + protected LongCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationCharObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationCharObjectHashMap.java new file mode 100755 index 00000000..b4eef4b9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationCharObjectHashMap.java @@ -0,0 +1,435 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link CharObjectHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link CharObjectHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationCharObjectHashMap implements CharObjectMap { + public final CharObjectHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationCharObjectHashMap( + CharObjectHashMap delegate, CharComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationCharObjectHashMap( + CharObjectHashMap delegate, CharObjectComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final char[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, CharComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + char[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, CharObjectComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final char[] keys = delegate.keys; + final VType[] values = (VType[]) delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator> iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(char key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(CharContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(CharObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public > T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final char[] keys = delegate.keys; + final VType[] values = (VType[]) delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public > T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final char[] keys = delegate.keys; + final VType[] values = (VType[]) delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public CharCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public ObjectContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public VType get(char key) { + return delegate.get(key); + } + + @Override + public VType getOrDefault(char key, VType defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public VType put(char key, VType value) { + throw readOnlyException(); + } + + @Override + public int putAll(CharObjectAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable> iterable) { + throw readOnlyException(); + } + + @Override + public VType remove(char key) { + throw readOnlyException(); + } + + @Override + public int indexOf(char key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public VType indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public VType indexReplace(int index, VType newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, char key, VType value) { + throw readOnlyException(); + } + + @Override + public VType indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final CharObjectCursor cursor = new CharObjectCursor(); + private int index; + + @Override + protected CharObjectCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = (VType) delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { + private final SortedIterationCharObjectHashMap owner = + SortedIterationCharObjectHashMap.this; + + @Override + public boolean contains(char e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((CharObjectProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((CharObjectPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final char e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final CharCursor cursor = new CharCursor(); + private int index; + + @Override + protected CharCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractObjectCollection { + private final SortedIterationCharObjectHashMap owner = + SortedIterationCharObjectHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(VType value) { + for (CharObjectCursor c : owner) { + if (java.util.Objects.equals(value, c.value)) { + return true; + } + } + return false; + } + + @Override + public > T forEach(T procedure) { + owner.forEach((CharObjectProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public > T forEach(T predicate) { + owner.forEach((CharObjectPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator> iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final VType e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator> { + private final ObjectCursor cursor = new ObjectCursor(); + private int index; + + @Override + protected ObjectCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = (VType) delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationCharShortHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationCharShortHashMap.java new file mode 100755 index 00000000..8097e0c0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationCharShortHashMap.java @@ -0,0 +1,441 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link CharShortHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link CharShortHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationCharShortHashMap implements CharShortMap { + public final CharShortHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationCharShortHashMap(CharShortHashMap delegate, CharComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationCharShortHashMap( + CharShortHashMap delegate, CharShortComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final char[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, CharComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + char[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, CharShortComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final char[] keys = delegate.keys; + final short[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(char key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(CharContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(CharShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final char[] keys = delegate.keys; + final short[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final char[] keys = delegate.keys; + final short[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public CharCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public ShortContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public short get(char key) { + return delegate.get(key); + } + + @Override + public short getOrDefault(char key, short defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public short put(char key, short value) { + throw readOnlyException(); + } + + @Override + public int putAll(CharShortAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public short putOrAdd(char key, short putValue, short incrementValue) { + throw readOnlyException(); + } + + @Override + public short addTo(char key, short additionValue) { + throw readOnlyException(); + } + + @Override + public short remove(char key) { + throw readOnlyException(); + } + + @Override + public int indexOf(char key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public short indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public short indexReplace(int index, short newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, char key, short value) { + throw readOnlyException(); + } + + @Override + public short indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final CharShortCursor cursor = new CharShortCursor(); + private int index; + + @Override + protected CharShortCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { + private final SortedIterationCharShortHashMap owner = SortedIterationCharShortHashMap.this; + + @Override + public boolean contains(char e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((CharShortProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((CharShortPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final char e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final CharCursor cursor = new CharCursor(); + private int index; + + @Override + protected CharCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractShortCollection { + private final SortedIterationCharShortHashMap owner = SortedIterationCharShortHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(short value) { + for (CharShortCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((CharShortProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((CharShortPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final short e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ShortCursor cursor = new ShortCursor(); + private int index; + + @Override + protected ShortCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationIntByteHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationIntByteHashMap.java new file mode 100755 index 00000000..ff9ca502 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationIntByteHashMap.java @@ -0,0 +1,440 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link IntByteHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link IntByteHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationIntByteHashMap implements IntByteMap { + public final IntByteHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationIntByteHashMap(IntByteHashMap delegate, IntComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationIntByteHashMap(IntByteHashMap delegate, IntByteComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final int[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, IntComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + int[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, IntByteComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final int[] keys = delegate.keys; + final byte[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(int key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(IntContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(IntBytePredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final int[] keys = delegate.keys; + final byte[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final int[] keys = delegate.keys; + final byte[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public IntCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public ByteContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public byte get(int key) { + return delegate.get(key); + } + + @Override + public byte getOrDefault(int key, byte defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public byte put(int key, byte value) { + throw readOnlyException(); + } + + @Override + public int putAll(IntByteAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public byte putOrAdd(int key, byte putValue, byte incrementValue) { + throw readOnlyException(); + } + + @Override + public byte addTo(int key, byte additionValue) { + throw readOnlyException(); + } + + @Override + public byte remove(int key) { + throw readOnlyException(); + } + + @Override + public int indexOf(int key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public byte indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public byte indexReplace(int index, byte newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, int key, byte value) { + throw readOnlyException(); + } + + @Override + public byte indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final IntByteCursor cursor = new IntByteCursor(); + private int index; + + @Override + protected IntByteCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { + private final SortedIterationIntByteHashMap owner = SortedIterationIntByteHashMap.this; + + @Override + public boolean contains(int e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((IntByteProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((IntBytePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final int e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final IntCursor cursor = new IntCursor(); + private int index; + + @Override + protected IntCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractByteCollection { + private final SortedIterationIntByteHashMap owner = SortedIterationIntByteHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(byte value) { + for (IntByteCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((IntByteProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((IntBytePredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final byte e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final BytePredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ByteCursor cursor = new ByteCursor(); + private int index; + + @Override + protected ByteCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationIntCharHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationIntCharHashMap.java new file mode 100755 index 00000000..c9190720 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationIntCharHashMap.java @@ -0,0 +1,440 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link IntCharHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link IntCharHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationIntCharHashMap implements IntCharMap { + public final IntCharHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationIntCharHashMap(IntCharHashMap delegate, IntComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationIntCharHashMap(IntCharHashMap delegate, IntCharComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final int[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, IntComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + int[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, IntCharComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final int[] keys = delegate.keys; + final char[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(int key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(IntContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(IntCharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final int[] keys = delegate.keys; + final char[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final int[] keys = delegate.keys; + final char[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public IntCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public CharContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public char get(int key) { + return delegate.get(key); + } + + @Override + public char getOrDefault(int key, char defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public char put(int key, char value) { + throw readOnlyException(); + } + + @Override + public int putAll(IntCharAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public char putOrAdd(int key, char putValue, char incrementValue) { + throw readOnlyException(); + } + + @Override + public char addTo(int key, char additionValue) { + throw readOnlyException(); + } + + @Override + public char remove(int key) { + throw readOnlyException(); + } + + @Override + public int indexOf(int key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public char indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public char indexReplace(int index, char newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, int key, char value) { + throw readOnlyException(); + } + + @Override + public char indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final IntCharCursor cursor = new IntCharCursor(); + private int index; + + @Override + protected IntCharCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { + private final SortedIterationIntCharHashMap owner = SortedIterationIntCharHashMap.this; + + @Override + public boolean contains(int e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((IntCharProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((IntCharPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final int e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final IntCursor cursor = new IntCursor(); + private int index; + + @Override + protected IntCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractCharCollection { + private final SortedIterationIntCharHashMap owner = SortedIterationIntCharHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(char value) { + for (IntCharCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((IntCharProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((IntCharPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final char e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final CharCursor cursor = new CharCursor(); + private int index; + + @Override + protected CharCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationIntDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationIntDoubleHashMap.java new file mode 100755 index 00000000..107abe8f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationIntDoubleHashMap.java @@ -0,0 +1,441 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link IntDoubleHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link IntDoubleHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationIntDoubleHashMap implements IntDoubleMap { + public final IntDoubleHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationIntDoubleHashMap(IntDoubleHashMap delegate, IntComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationIntDoubleHashMap( + IntDoubleHashMap delegate, IntDoubleComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final int[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, IntComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + int[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, IntDoubleComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final int[] keys = delegate.keys; + final double[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(int key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(IntContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(IntDoublePredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final int[] keys = delegate.keys; + final double[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final int[] keys = delegate.keys; + final double[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public IntCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public DoubleContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public double get(int key) { + return delegate.get(key); + } + + @Override + public double getOrDefault(int key, double defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public double put(int key, double value) { + throw readOnlyException(); + } + + @Override + public int putAll(IntDoubleAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public double putOrAdd(int key, double putValue, double incrementValue) { + throw readOnlyException(); + } + + @Override + public double addTo(int key, double additionValue) { + throw readOnlyException(); + } + + @Override + public double remove(int key) { + throw readOnlyException(); + } + + @Override + public int indexOf(int key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public double indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public double indexReplace(int index, double newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, int key, double value) { + throw readOnlyException(); + } + + @Override + public double indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final IntDoubleCursor cursor = new IntDoubleCursor(); + private int index; + + @Override + protected IntDoubleCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { + private final SortedIterationIntDoubleHashMap owner = SortedIterationIntDoubleHashMap.this; + + @Override + public boolean contains(int e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((IntDoubleProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((IntDoublePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final int e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final IntCursor cursor = new IntCursor(); + private int index; + + @Override + protected IntCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractDoubleCollection { + private final SortedIterationIntDoubleHashMap owner = SortedIterationIntDoubleHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(double value) { + for (IntDoubleCursor c : owner) { + if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((IntDoubleProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((IntDoublePredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final double e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final DoublePredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final DoubleCursor cursor = new DoubleCursor(); + private int index; + + @Override + protected DoubleCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationIntFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationIntFloatHashMap.java new file mode 100755 index 00000000..ff98b064 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationIntFloatHashMap.java @@ -0,0 +1,440 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link IntFloatHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link IntFloatHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationIntFloatHashMap implements IntFloatMap { + public final IntFloatHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationIntFloatHashMap(IntFloatHashMap delegate, IntComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationIntFloatHashMap(IntFloatHashMap delegate, IntFloatComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final int[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, IntComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + int[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, IntFloatComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final int[] keys = delegate.keys; + final float[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(int key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(IntContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(IntFloatPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final int[] keys = delegate.keys; + final float[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final int[] keys = delegate.keys; + final float[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public IntCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public FloatContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public float get(int key) { + return delegate.get(key); + } + + @Override + public float getOrDefault(int key, float defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public float put(int key, float value) { + throw readOnlyException(); + } + + @Override + public int putAll(IntFloatAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public float putOrAdd(int key, float putValue, float incrementValue) { + throw readOnlyException(); + } + + @Override + public float addTo(int key, float additionValue) { + throw readOnlyException(); + } + + @Override + public float remove(int key) { + throw readOnlyException(); + } + + @Override + public int indexOf(int key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public float indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public float indexReplace(int index, float newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, int key, float value) { + throw readOnlyException(); + } + + @Override + public float indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final IntFloatCursor cursor = new IntFloatCursor(); + private int index; + + @Override + protected IntFloatCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { + private final SortedIterationIntFloatHashMap owner = SortedIterationIntFloatHashMap.this; + + @Override + public boolean contains(int e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((IntFloatProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((IntFloatPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final int e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final IntCursor cursor = new IntCursor(); + private int index; + + @Override + protected IntCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractFloatCollection { + private final SortedIterationIntFloatHashMap owner = SortedIterationIntFloatHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(float value) { + for (IntFloatCursor c : owner) { + if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((IntFloatProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((IntFloatPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final float e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final FloatPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final FloatCursor cursor = new FloatCursor(); + private int index; + + @Override + protected FloatCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationIntIntHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationIntIntHashMap.java new file mode 100755 index 00000000..8cb4c22c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationIntIntHashMap.java @@ -0,0 +1,440 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link IntIntHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link IntIntHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationIntIntHashMap implements IntIntMap { + public final IntIntHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationIntIntHashMap(IntIntHashMap delegate, IntComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationIntIntHashMap(IntIntHashMap delegate, IntIntComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final int[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, IntComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + int[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, IntIntComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final int[] keys = delegate.keys; + final int[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(int key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(IntContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(IntIntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final int[] keys = delegate.keys; + final int[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final int[] keys = delegate.keys; + final int[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public IntCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public IntContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public int get(int key) { + return delegate.get(key); + } + + @Override + public int getOrDefault(int key, int defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public int put(int key, int value) { + throw readOnlyException(); + } + + @Override + public int putAll(IntIntAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public int putOrAdd(int key, int putValue, int incrementValue) { + throw readOnlyException(); + } + + @Override + public int addTo(int key, int additionValue) { + throw readOnlyException(); + } + + @Override + public int remove(int key) { + throw readOnlyException(); + } + + @Override + public int indexOf(int key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public int indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public int indexReplace(int index, int newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, int key, int value) { + throw readOnlyException(); + } + + @Override + public int indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final IntIntCursor cursor = new IntIntCursor(); + private int index; + + @Override + protected IntIntCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { + private final SortedIterationIntIntHashMap owner = SortedIterationIntIntHashMap.this; + + @Override + public boolean contains(int e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((IntIntProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((IntIntPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final int e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final IntCursor cursor = new IntCursor(); + private int index; + + @Override + protected IntCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractIntCollection { + private final SortedIterationIntIntHashMap owner = SortedIterationIntIntHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(int value) { + for (IntIntCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((IntIntProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((IntIntPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final int e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final IntCursor cursor = new IntCursor(); + private int index; + + @Override + protected IntCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationIntLongHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationIntLongHashMap.java new file mode 100755 index 00000000..bbbfb306 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationIntLongHashMap.java @@ -0,0 +1,440 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link IntLongHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link IntLongHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationIntLongHashMap implements IntLongMap { + public final IntLongHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationIntLongHashMap(IntLongHashMap delegate, IntComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationIntLongHashMap(IntLongHashMap delegate, IntLongComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final int[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, IntComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + int[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, IntLongComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final int[] keys = delegate.keys; + final long[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(int key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(IntContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(IntLongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final int[] keys = delegate.keys; + final long[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final int[] keys = delegate.keys; + final long[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public IntCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public LongContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public long get(int key) { + return delegate.get(key); + } + + @Override + public long getOrDefault(int key, long defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public long put(int key, long value) { + throw readOnlyException(); + } + + @Override + public int putAll(IntLongAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public long putOrAdd(int key, long putValue, long incrementValue) { + throw readOnlyException(); + } + + @Override + public long addTo(int key, long additionValue) { + throw readOnlyException(); + } + + @Override + public long remove(int key) { + throw readOnlyException(); + } + + @Override + public int indexOf(int key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public long indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public long indexReplace(int index, long newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, int key, long value) { + throw readOnlyException(); + } + + @Override + public long indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final IntLongCursor cursor = new IntLongCursor(); + private int index; + + @Override + protected IntLongCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { + private final SortedIterationIntLongHashMap owner = SortedIterationIntLongHashMap.this; + + @Override + public boolean contains(int e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((IntLongProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((IntLongPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final int e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final IntCursor cursor = new IntCursor(); + private int index; + + @Override + protected IntCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractLongCollection { + private final SortedIterationIntLongHashMap owner = SortedIterationIntLongHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(long value) { + for (IntLongCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((IntLongProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((IntLongPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final long e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final LongCursor cursor = new LongCursor(); + private int index; + + @Override + protected LongCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationIntObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationIntObjectHashMap.java new file mode 100755 index 00000000..cd8591ef --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationIntObjectHashMap.java @@ -0,0 +1,435 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link IntObjectHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link IntObjectHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationIntObjectHashMap implements IntObjectMap { + public final IntObjectHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationIntObjectHashMap( + IntObjectHashMap delegate, IntComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationIntObjectHashMap( + IntObjectHashMap delegate, IntObjectComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final int[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, IntComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + int[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, IntObjectComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final int[] keys = delegate.keys; + final VType[] values = (VType[]) delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator> iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(int key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(IntContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(IntObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public > T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final int[] keys = delegate.keys; + final VType[] values = (VType[]) delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public > T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final int[] keys = delegate.keys; + final VType[] values = (VType[]) delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public IntCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public ObjectContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public VType get(int key) { + return delegate.get(key); + } + + @Override + public VType getOrDefault(int key, VType defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public VType put(int key, VType value) { + throw readOnlyException(); + } + + @Override + public int putAll(IntObjectAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable> iterable) { + throw readOnlyException(); + } + + @Override + public VType remove(int key) { + throw readOnlyException(); + } + + @Override + public int indexOf(int key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public VType indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public VType indexReplace(int index, VType newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, int key, VType value) { + throw readOnlyException(); + } + + @Override + public VType indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final IntObjectCursor cursor = new IntObjectCursor(); + private int index; + + @Override + protected IntObjectCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = (VType) delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { + private final SortedIterationIntObjectHashMap owner = + SortedIterationIntObjectHashMap.this; + + @Override + public boolean contains(int e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((IntObjectProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((IntObjectPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final int e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final IntCursor cursor = new IntCursor(); + private int index; + + @Override + protected IntCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractObjectCollection { + private final SortedIterationIntObjectHashMap owner = + SortedIterationIntObjectHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(VType value) { + for (IntObjectCursor c : owner) { + if (java.util.Objects.equals(value, c.value)) { + return true; + } + } + return false; + } + + @Override + public > T forEach(T procedure) { + owner.forEach((IntObjectProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public > T forEach(T predicate) { + owner.forEach((IntObjectPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator> iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final VType e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator> { + private final ObjectCursor cursor = new ObjectCursor(); + private int index; + + @Override + protected ObjectCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = (VType) delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationIntShortHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationIntShortHashMap.java new file mode 100755 index 00000000..243bf989 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationIntShortHashMap.java @@ -0,0 +1,440 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link IntShortHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link IntShortHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationIntShortHashMap implements IntShortMap { + public final IntShortHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationIntShortHashMap(IntShortHashMap delegate, IntComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationIntShortHashMap(IntShortHashMap delegate, IntShortComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final int[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, IntComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + int[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, IntShortComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final int[] keys = delegate.keys; + final short[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(int key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(IntContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(IntShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final int[] keys = delegate.keys; + final short[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final int[] keys = delegate.keys; + final short[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public IntCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public ShortContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public short get(int key) { + return delegate.get(key); + } + + @Override + public short getOrDefault(int key, short defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public short put(int key, short value) { + throw readOnlyException(); + } + + @Override + public int putAll(IntShortAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public short putOrAdd(int key, short putValue, short incrementValue) { + throw readOnlyException(); + } + + @Override + public short addTo(int key, short additionValue) { + throw readOnlyException(); + } + + @Override + public short remove(int key) { + throw readOnlyException(); + } + + @Override + public int indexOf(int key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public short indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public short indexReplace(int index, short newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, int key, short value) { + throw readOnlyException(); + } + + @Override + public short indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final IntShortCursor cursor = new IntShortCursor(); + private int index; + + @Override + protected IntShortCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractIntCollection implements IntLookupContainer { + private final SortedIterationIntShortHashMap owner = SortedIterationIntShortHashMap.this; + + @Override + public boolean contains(int e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((IntShortProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((IntShortPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final int e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final IntCursor cursor = new IntCursor(); + private int index; + + @Override + protected IntCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractShortCollection { + private final SortedIterationIntShortHashMap owner = SortedIterationIntShortHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(short value) { + for (IntShortCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((IntShortProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((IntShortPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final short e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ShortCursor cursor = new ShortCursor(); + private int index; + + @Override + protected ShortCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationLongByteHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationLongByteHashMap.java new file mode 100755 index 00000000..46b063f7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationLongByteHashMap.java @@ -0,0 +1,440 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link LongByteHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link LongByteHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationLongByteHashMap implements LongByteMap { + public final LongByteHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationLongByteHashMap(LongByteHashMap delegate, LongComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationLongByteHashMap(LongByteHashMap delegate, LongByteComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final long[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, LongComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + long[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, LongByteComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final long[] keys = delegate.keys; + final byte[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(long key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(LongContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(LongBytePredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final long[] keys = delegate.keys; + final byte[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final long[] keys = delegate.keys; + final byte[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public LongCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public ByteContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public byte get(long key) { + return delegate.get(key); + } + + @Override + public byte getOrDefault(long key, byte defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public byte put(long key, byte value) { + throw readOnlyException(); + } + + @Override + public int putAll(LongByteAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public byte putOrAdd(long key, byte putValue, byte incrementValue) { + throw readOnlyException(); + } + + @Override + public byte addTo(long key, byte additionValue) { + throw readOnlyException(); + } + + @Override + public byte remove(long key) { + throw readOnlyException(); + } + + @Override + public int indexOf(long key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public byte indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public byte indexReplace(int index, byte newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, long key, byte value) { + throw readOnlyException(); + } + + @Override + public byte indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final LongByteCursor cursor = new LongByteCursor(); + private int index; + + @Override + protected LongByteCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { + private final SortedIterationLongByteHashMap owner = SortedIterationLongByteHashMap.this; + + @Override + public boolean contains(long e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((LongByteProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((LongBytePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final long e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final LongCursor cursor = new LongCursor(); + private int index; + + @Override + protected LongCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractByteCollection { + private final SortedIterationLongByteHashMap owner = SortedIterationLongByteHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(byte value) { + for (LongByteCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((LongByteProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((LongBytePredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final byte e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final BytePredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ByteCursor cursor = new ByteCursor(); + private int index; + + @Override + protected ByteCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationLongCharHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationLongCharHashMap.java new file mode 100755 index 00000000..c4daf3d0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationLongCharHashMap.java @@ -0,0 +1,440 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link LongCharHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link LongCharHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationLongCharHashMap implements LongCharMap { + public final LongCharHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationLongCharHashMap(LongCharHashMap delegate, LongComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationLongCharHashMap(LongCharHashMap delegate, LongCharComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final long[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, LongComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + long[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, LongCharComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final long[] keys = delegate.keys; + final char[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(long key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(LongContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(LongCharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final long[] keys = delegate.keys; + final char[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final long[] keys = delegate.keys; + final char[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public LongCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public CharContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public char get(long key) { + return delegate.get(key); + } + + @Override + public char getOrDefault(long key, char defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public char put(long key, char value) { + throw readOnlyException(); + } + + @Override + public int putAll(LongCharAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public char putOrAdd(long key, char putValue, char incrementValue) { + throw readOnlyException(); + } + + @Override + public char addTo(long key, char additionValue) { + throw readOnlyException(); + } + + @Override + public char remove(long key) { + throw readOnlyException(); + } + + @Override + public int indexOf(long key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public char indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public char indexReplace(int index, char newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, long key, char value) { + throw readOnlyException(); + } + + @Override + public char indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final LongCharCursor cursor = new LongCharCursor(); + private int index; + + @Override + protected LongCharCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { + private final SortedIterationLongCharHashMap owner = SortedIterationLongCharHashMap.this; + + @Override + public boolean contains(long e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((LongCharProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((LongCharPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final long e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final LongCursor cursor = new LongCursor(); + private int index; + + @Override + protected LongCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractCharCollection { + private final SortedIterationLongCharHashMap owner = SortedIterationLongCharHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(char value) { + for (LongCharCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((LongCharProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((LongCharPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final char e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final CharCursor cursor = new CharCursor(); + private int index; + + @Override + protected CharCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationLongDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationLongDoubleHashMap.java new file mode 100755 index 00000000..bbd41530 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationLongDoubleHashMap.java @@ -0,0 +1,441 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link LongDoubleHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link LongDoubleHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationLongDoubleHashMap implements LongDoubleMap { + public final LongDoubleHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationLongDoubleHashMap(LongDoubleHashMap delegate, LongComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationLongDoubleHashMap( + LongDoubleHashMap delegate, LongDoubleComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final long[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, LongComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + long[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, LongDoubleComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final long[] keys = delegate.keys; + final double[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(long key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(LongContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(LongDoublePredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final long[] keys = delegate.keys; + final double[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final long[] keys = delegate.keys; + final double[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public LongCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public DoubleContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public double get(long key) { + return delegate.get(key); + } + + @Override + public double getOrDefault(long key, double defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public double put(long key, double value) { + throw readOnlyException(); + } + + @Override + public int putAll(LongDoubleAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public double putOrAdd(long key, double putValue, double incrementValue) { + throw readOnlyException(); + } + + @Override + public double addTo(long key, double additionValue) { + throw readOnlyException(); + } + + @Override + public double remove(long key) { + throw readOnlyException(); + } + + @Override + public int indexOf(long key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public double indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public double indexReplace(int index, double newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, long key, double value) { + throw readOnlyException(); + } + + @Override + public double indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final LongDoubleCursor cursor = new LongDoubleCursor(); + private int index; + + @Override + protected LongDoubleCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { + private final SortedIterationLongDoubleHashMap owner = SortedIterationLongDoubleHashMap.this; + + @Override + public boolean contains(long e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((LongDoubleProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((LongDoublePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final long e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final LongCursor cursor = new LongCursor(); + private int index; + + @Override + protected LongCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractDoubleCollection { + private final SortedIterationLongDoubleHashMap owner = SortedIterationLongDoubleHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(double value) { + for (LongDoubleCursor c : owner) { + if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((LongDoubleProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((LongDoublePredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final double e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final DoublePredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final DoubleCursor cursor = new DoubleCursor(); + private int index; + + @Override + protected DoubleCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationLongFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationLongFloatHashMap.java new file mode 100755 index 00000000..2a8e61d2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationLongFloatHashMap.java @@ -0,0 +1,441 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link LongFloatHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link LongFloatHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationLongFloatHashMap implements LongFloatMap { + public final LongFloatHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationLongFloatHashMap(LongFloatHashMap delegate, LongComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationLongFloatHashMap( + LongFloatHashMap delegate, LongFloatComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final long[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, LongComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + long[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, LongFloatComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final long[] keys = delegate.keys; + final float[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(long key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(LongContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(LongFloatPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final long[] keys = delegate.keys; + final float[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final long[] keys = delegate.keys; + final float[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public LongCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public FloatContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public float get(long key) { + return delegate.get(key); + } + + @Override + public float getOrDefault(long key, float defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public float put(long key, float value) { + throw readOnlyException(); + } + + @Override + public int putAll(LongFloatAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public float putOrAdd(long key, float putValue, float incrementValue) { + throw readOnlyException(); + } + + @Override + public float addTo(long key, float additionValue) { + throw readOnlyException(); + } + + @Override + public float remove(long key) { + throw readOnlyException(); + } + + @Override + public int indexOf(long key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public float indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public float indexReplace(int index, float newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, long key, float value) { + throw readOnlyException(); + } + + @Override + public float indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final LongFloatCursor cursor = new LongFloatCursor(); + private int index; + + @Override + protected LongFloatCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { + private final SortedIterationLongFloatHashMap owner = SortedIterationLongFloatHashMap.this; + + @Override + public boolean contains(long e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((LongFloatProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((LongFloatPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final long e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final LongCursor cursor = new LongCursor(); + private int index; + + @Override + protected LongCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractFloatCollection { + private final SortedIterationLongFloatHashMap owner = SortedIterationLongFloatHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(float value) { + for (LongFloatCursor c : owner) { + if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((LongFloatProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((LongFloatPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final float e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final FloatPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final FloatCursor cursor = new FloatCursor(); + private int index; + + @Override + protected FloatCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationLongIntHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationLongIntHashMap.java new file mode 100755 index 00000000..77620aa9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationLongIntHashMap.java @@ -0,0 +1,440 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link LongIntHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link LongIntHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationLongIntHashMap implements LongIntMap { + public final LongIntHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationLongIntHashMap(LongIntHashMap delegate, LongComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationLongIntHashMap(LongIntHashMap delegate, LongIntComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final long[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, LongComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + long[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, LongIntComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final long[] keys = delegate.keys; + final int[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(long key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(LongContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(LongIntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final long[] keys = delegate.keys; + final int[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final long[] keys = delegate.keys; + final int[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public LongCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public IntContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public int get(long key) { + return delegate.get(key); + } + + @Override + public int getOrDefault(long key, int defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public int put(long key, int value) { + throw readOnlyException(); + } + + @Override + public int putAll(LongIntAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public int putOrAdd(long key, int putValue, int incrementValue) { + throw readOnlyException(); + } + + @Override + public int addTo(long key, int additionValue) { + throw readOnlyException(); + } + + @Override + public int remove(long key) { + throw readOnlyException(); + } + + @Override + public int indexOf(long key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public int indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public int indexReplace(int index, int newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, long key, int value) { + throw readOnlyException(); + } + + @Override + public int indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final LongIntCursor cursor = new LongIntCursor(); + private int index; + + @Override + protected LongIntCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { + private final SortedIterationLongIntHashMap owner = SortedIterationLongIntHashMap.this; + + @Override + public boolean contains(long e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((LongIntProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((LongIntPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final long e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final LongCursor cursor = new LongCursor(); + private int index; + + @Override + protected LongCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractIntCollection { + private final SortedIterationLongIntHashMap owner = SortedIterationLongIntHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(int value) { + for (LongIntCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((LongIntProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((LongIntPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final int e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final IntCursor cursor = new IntCursor(); + private int index; + + @Override + protected IntCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationLongLongHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationLongLongHashMap.java new file mode 100755 index 00000000..605189b3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationLongLongHashMap.java @@ -0,0 +1,440 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link LongLongHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link LongLongHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationLongLongHashMap implements LongLongMap { + public final LongLongHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationLongLongHashMap(LongLongHashMap delegate, LongComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationLongLongHashMap(LongLongHashMap delegate, LongLongComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final long[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, LongComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + long[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, LongLongComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final long[] keys = delegate.keys; + final long[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(long key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(LongContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(LongLongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final long[] keys = delegate.keys; + final long[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final long[] keys = delegate.keys; + final long[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public LongCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public LongContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public long get(long key) { + return delegate.get(key); + } + + @Override + public long getOrDefault(long key, long defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public long put(long key, long value) { + throw readOnlyException(); + } + + @Override + public int putAll(LongLongAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public long putOrAdd(long key, long putValue, long incrementValue) { + throw readOnlyException(); + } + + @Override + public long addTo(long key, long additionValue) { + throw readOnlyException(); + } + + @Override + public long remove(long key) { + throw readOnlyException(); + } + + @Override + public int indexOf(long key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public long indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public long indexReplace(int index, long newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, long key, long value) { + throw readOnlyException(); + } + + @Override + public long indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final LongLongCursor cursor = new LongLongCursor(); + private int index; + + @Override + protected LongLongCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { + private final SortedIterationLongLongHashMap owner = SortedIterationLongLongHashMap.this; + + @Override + public boolean contains(long e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((LongLongProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((LongLongPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final long e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final LongCursor cursor = new LongCursor(); + private int index; + + @Override + protected LongCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractLongCollection { + private final SortedIterationLongLongHashMap owner = SortedIterationLongLongHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(long value) { + for (LongLongCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((LongLongProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((LongLongPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final long e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final LongCursor cursor = new LongCursor(); + private int index; + + @Override + protected LongCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationLongObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationLongObjectHashMap.java new file mode 100755 index 00000000..b7f64fe4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationLongObjectHashMap.java @@ -0,0 +1,435 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link LongObjectHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link LongObjectHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationLongObjectHashMap implements LongObjectMap { + public final LongObjectHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationLongObjectHashMap( + LongObjectHashMap delegate, LongComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationLongObjectHashMap( + LongObjectHashMap delegate, LongObjectComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final long[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, LongComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + long[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, LongObjectComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final long[] keys = delegate.keys; + final VType[] values = (VType[]) delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator> iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(long key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(LongContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(LongObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public > T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final long[] keys = delegate.keys; + final VType[] values = (VType[]) delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public > T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final long[] keys = delegate.keys; + final VType[] values = (VType[]) delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public LongCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public ObjectContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public VType get(long key) { + return delegate.get(key); + } + + @Override + public VType getOrDefault(long key, VType defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public VType put(long key, VType value) { + throw readOnlyException(); + } + + @Override + public int putAll(LongObjectAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable> iterable) { + throw readOnlyException(); + } + + @Override + public VType remove(long key) { + throw readOnlyException(); + } + + @Override + public int indexOf(long key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public VType indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public VType indexReplace(int index, VType newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, long key, VType value) { + throw readOnlyException(); + } + + @Override + public VType indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final LongObjectCursor cursor = new LongObjectCursor(); + private int index; + + @Override + protected LongObjectCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = (VType) delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { + private final SortedIterationLongObjectHashMap owner = + SortedIterationLongObjectHashMap.this; + + @Override + public boolean contains(long e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((LongObjectProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((LongObjectPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final long e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final LongCursor cursor = new LongCursor(); + private int index; + + @Override + protected LongCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractObjectCollection { + private final SortedIterationLongObjectHashMap owner = + SortedIterationLongObjectHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(VType value) { + for (LongObjectCursor c : owner) { + if (java.util.Objects.equals(value, c.value)) { + return true; + } + } + return false; + } + + @Override + public > T forEach(T procedure) { + owner.forEach((LongObjectProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public > T forEach(T predicate) { + owner.forEach((LongObjectPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator> iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final VType e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator> { + private final ObjectCursor cursor = new ObjectCursor(); + private int index; + + @Override + protected ObjectCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = (VType) delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationLongShortHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationLongShortHashMap.java new file mode 100755 index 00000000..63de5c26 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationLongShortHashMap.java @@ -0,0 +1,441 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link LongShortHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link LongShortHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationLongShortHashMap implements LongShortMap { + public final LongShortHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationLongShortHashMap(LongShortHashMap delegate, LongComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationLongShortHashMap( + LongShortHashMap delegate, LongShortComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final long[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, LongComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + long[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, LongShortComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final long[] keys = delegate.keys; + final short[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(long key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(LongContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(LongShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final long[] keys = delegate.keys; + final short[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final long[] keys = delegate.keys; + final short[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public LongCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public ShortContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public short get(long key) { + return delegate.get(key); + } + + @Override + public short getOrDefault(long key, short defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public short put(long key, short value) { + throw readOnlyException(); + } + + @Override + public int putAll(LongShortAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public short putOrAdd(long key, short putValue, short incrementValue) { + throw readOnlyException(); + } + + @Override + public short addTo(long key, short additionValue) { + throw readOnlyException(); + } + + @Override + public short remove(long key) { + throw readOnlyException(); + } + + @Override + public int indexOf(long key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public short indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public short indexReplace(int index, short newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, long key, short value) { + throw readOnlyException(); + } + + @Override + public short indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final LongShortCursor cursor = new LongShortCursor(); + private int index; + + @Override + protected LongShortCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractLongCollection implements LongLookupContainer { + private final SortedIterationLongShortHashMap owner = SortedIterationLongShortHashMap.this; + + @Override + public boolean contains(long e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((LongShortProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((LongShortPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final long e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final LongCursor cursor = new LongCursor(); + private int index; + + @Override + protected LongCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractShortCollection { + private final SortedIterationLongShortHashMap owner = SortedIterationLongShortHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(short value) { + for (LongShortCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((LongShortProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((LongShortPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final short e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ShortCursor cursor = new ShortCursor(); + private int index; + + @Override + protected ShortCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationObjectByteHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectByteHashMap.java new file mode 100755 index 00000000..011ace2f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectByteHashMap.java @@ -0,0 +1,447 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Comparator; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link ObjectByteHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link ObjectByteHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationObjectByteHashMap implements ObjectByteMap { + public final ObjectByteHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationObjectByteHashMap( + ObjectByteHashMap delegate, Comparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationObjectByteHashMap( + ObjectByteHashMap delegate, ObjectByteComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final KType[] keys = (KType[]) delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!(((KType) keys[keyIndex]) == null)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, Comparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + KType[] keys = (KType[]) delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, ObjectByteComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final KType[] keys = (KType[]) delegate.keys; + final byte[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator> iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(KType key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(ObjectContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectBytePredicate predicate) { + throw readOnlyException(); + } + + @Override + public > T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final KType[] keys = (KType[]) delegate.keys; + final byte[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public > T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final KType[] keys = (KType[]) delegate.keys; + final byte[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public ObjectCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public ByteContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public byte get(KType key) { + return delegate.get(key); + } + + @Override + public byte getOrDefault(KType key, byte defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public byte put(KType key, byte value) { + throw readOnlyException(); + } + + @Override + public int putAll(ObjectByteAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable> iterable) { + throw readOnlyException(); + } + + @Override + public byte putOrAdd(KType key, byte putValue, byte incrementValue) { + throw readOnlyException(); + } + + @Override + public byte addTo(KType key, byte additionValue) { + throw readOnlyException(); + } + + @Override + public byte remove(KType key) { + throw readOnlyException(); + } + + @Override + public int indexOf(KType key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public byte indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public byte indexReplace(int index, byte newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, KType key, byte value) { + throw readOnlyException(); + } + + @Override + public byte indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final ObjectByteCursor cursor = new ObjectByteCursor(); + private int index; + + @Override + protected ObjectByteCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = (KType) delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractObjectCollection + implements ObjectLookupContainer { + private final SortedIterationObjectByteHashMap owner = + SortedIterationObjectByteHashMap.this; + + @Override + public boolean contains(KType e) { + return owner.containsKey(e); + } + + @Override + public > T forEach(final T procedure) { + owner.forEach((ObjectByteProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public > T forEach(final T predicate) { + owner.forEach((ObjectBytePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator> iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final KType e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator> { + private final ObjectCursor cursor = new ObjectCursor(); + private int index; + + @Override + protected ObjectCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = (KType) delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractByteCollection { + private final SortedIterationObjectByteHashMap owner = + SortedIterationObjectByteHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(byte value) { + for (ObjectByteCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((ObjectByteProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((ObjectBytePredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final byte e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final BytePredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ByteCursor cursor = new ByteCursor(); + private int index; + + @Override + protected ByteCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationObjectCharHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectCharHashMap.java new file mode 100755 index 00000000..37f0f25a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectCharHashMap.java @@ -0,0 +1,447 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Comparator; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link ObjectCharHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link ObjectCharHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationObjectCharHashMap implements ObjectCharMap { + public final ObjectCharHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationObjectCharHashMap( + ObjectCharHashMap delegate, Comparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationObjectCharHashMap( + ObjectCharHashMap delegate, ObjectCharComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final KType[] keys = (KType[]) delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!(((KType) keys[keyIndex]) == null)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, Comparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + KType[] keys = (KType[]) delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, ObjectCharComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final KType[] keys = (KType[]) delegate.keys; + final char[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator> iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(KType key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(ObjectContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectCharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public > T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final KType[] keys = (KType[]) delegate.keys; + final char[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public > T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final KType[] keys = (KType[]) delegate.keys; + final char[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public ObjectCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public CharContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public char get(KType key) { + return delegate.get(key); + } + + @Override + public char getOrDefault(KType key, char defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public char put(KType key, char value) { + throw readOnlyException(); + } + + @Override + public int putAll(ObjectCharAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable> iterable) { + throw readOnlyException(); + } + + @Override + public char putOrAdd(KType key, char putValue, char incrementValue) { + throw readOnlyException(); + } + + @Override + public char addTo(KType key, char additionValue) { + throw readOnlyException(); + } + + @Override + public char remove(KType key) { + throw readOnlyException(); + } + + @Override + public int indexOf(KType key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public char indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public char indexReplace(int index, char newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, KType key, char value) { + throw readOnlyException(); + } + + @Override + public char indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final ObjectCharCursor cursor = new ObjectCharCursor(); + private int index; + + @Override + protected ObjectCharCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = (KType) delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractObjectCollection + implements ObjectLookupContainer { + private final SortedIterationObjectCharHashMap owner = + SortedIterationObjectCharHashMap.this; + + @Override + public boolean contains(KType e) { + return owner.containsKey(e); + } + + @Override + public > T forEach(final T procedure) { + owner.forEach((ObjectCharProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public > T forEach(final T predicate) { + owner.forEach((ObjectCharPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator> iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final KType e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator> { + private final ObjectCursor cursor = new ObjectCursor(); + private int index; + + @Override + protected ObjectCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = (KType) delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractCharCollection { + private final SortedIterationObjectCharHashMap owner = + SortedIterationObjectCharHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(char value) { + for (ObjectCharCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((ObjectCharProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((ObjectCharPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final char e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final CharCursor cursor = new CharCursor(); + private int index; + + @Override + protected CharCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationObjectDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectDoubleHashMap.java new file mode 100755 index 00000000..f593fe6a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectDoubleHashMap.java @@ -0,0 +1,447 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Comparator; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link ObjectDoubleHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link ObjectDoubleHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationObjectDoubleHashMap implements ObjectDoubleMap { + public final ObjectDoubleHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationObjectDoubleHashMap( + ObjectDoubleHashMap delegate, Comparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationObjectDoubleHashMap( + ObjectDoubleHashMap delegate, ObjectDoubleComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final KType[] keys = (KType[]) delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!(((KType) keys[keyIndex]) == null)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, Comparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + KType[] keys = (KType[]) delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, ObjectDoubleComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final KType[] keys = (KType[]) delegate.keys; + final double[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator> iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(KType key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(ObjectContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectDoublePredicate predicate) { + throw readOnlyException(); + } + + @Override + public > T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final KType[] keys = (KType[]) delegate.keys; + final double[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public > T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final KType[] keys = (KType[]) delegate.keys; + final double[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public ObjectCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public DoubleContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public double get(KType key) { + return delegate.get(key); + } + + @Override + public double getOrDefault(KType key, double defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public double put(KType key, double value) { + throw readOnlyException(); + } + + @Override + public int putAll(ObjectDoubleAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable> iterable) { + throw readOnlyException(); + } + + @Override + public double putOrAdd(KType key, double putValue, double incrementValue) { + throw readOnlyException(); + } + + @Override + public double addTo(KType key, double additionValue) { + throw readOnlyException(); + } + + @Override + public double remove(KType key) { + throw readOnlyException(); + } + + @Override + public int indexOf(KType key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public double indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public double indexReplace(int index, double newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, KType key, double value) { + throw readOnlyException(); + } + + @Override + public double indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final ObjectDoubleCursor cursor = new ObjectDoubleCursor(); + private int index; + + @Override + protected ObjectDoubleCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = (KType) delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractObjectCollection + implements ObjectLookupContainer { + private final SortedIterationObjectDoubleHashMap owner = + SortedIterationObjectDoubleHashMap.this; + + @Override + public boolean contains(KType e) { + return owner.containsKey(e); + } + + @Override + public > T forEach(final T procedure) { + owner.forEach((ObjectDoubleProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public > T forEach(final T predicate) { + owner.forEach((ObjectDoublePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator> iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final KType e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator> { + private final ObjectCursor cursor = new ObjectCursor(); + private int index; + + @Override + protected ObjectCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = (KType) delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractDoubleCollection { + private final SortedIterationObjectDoubleHashMap owner = + SortedIterationObjectDoubleHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(double value) { + for (ObjectDoubleCursor c : owner) { + if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((ObjectDoubleProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((ObjectDoublePredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final double e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final DoublePredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final DoubleCursor cursor = new DoubleCursor(); + private int index; + + @Override + protected DoubleCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationObjectFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectFloatHashMap.java new file mode 100755 index 00000000..4781dd42 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectFloatHashMap.java @@ -0,0 +1,447 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Comparator; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link ObjectFloatHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link ObjectFloatHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationObjectFloatHashMap implements ObjectFloatMap { + public final ObjectFloatHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationObjectFloatHashMap( + ObjectFloatHashMap delegate, Comparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationObjectFloatHashMap( + ObjectFloatHashMap delegate, ObjectFloatComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final KType[] keys = (KType[]) delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!(((KType) keys[keyIndex]) == null)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, Comparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + KType[] keys = (KType[]) delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, ObjectFloatComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final KType[] keys = (KType[]) delegate.keys; + final float[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator> iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(KType key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(ObjectContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectFloatPredicate predicate) { + throw readOnlyException(); + } + + @Override + public > T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final KType[] keys = (KType[]) delegate.keys; + final float[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public > T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final KType[] keys = (KType[]) delegate.keys; + final float[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public ObjectCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public FloatContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public float get(KType key) { + return delegate.get(key); + } + + @Override + public float getOrDefault(KType key, float defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public float put(KType key, float value) { + throw readOnlyException(); + } + + @Override + public int putAll(ObjectFloatAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable> iterable) { + throw readOnlyException(); + } + + @Override + public float putOrAdd(KType key, float putValue, float incrementValue) { + throw readOnlyException(); + } + + @Override + public float addTo(KType key, float additionValue) { + throw readOnlyException(); + } + + @Override + public float remove(KType key) { + throw readOnlyException(); + } + + @Override + public int indexOf(KType key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public float indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public float indexReplace(int index, float newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, KType key, float value) { + throw readOnlyException(); + } + + @Override + public float indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final ObjectFloatCursor cursor = new ObjectFloatCursor(); + private int index; + + @Override + protected ObjectFloatCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = (KType) delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractObjectCollection + implements ObjectLookupContainer { + private final SortedIterationObjectFloatHashMap owner = + SortedIterationObjectFloatHashMap.this; + + @Override + public boolean contains(KType e) { + return owner.containsKey(e); + } + + @Override + public > T forEach(final T procedure) { + owner.forEach((ObjectFloatProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public > T forEach(final T predicate) { + owner.forEach((ObjectFloatPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator> iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final KType e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator> { + private final ObjectCursor cursor = new ObjectCursor(); + private int index; + + @Override + protected ObjectCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = (KType) delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractFloatCollection { + private final SortedIterationObjectFloatHashMap owner = + SortedIterationObjectFloatHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(float value) { + for (ObjectFloatCursor c : owner) { + if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((ObjectFloatProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((ObjectFloatPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final float e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final FloatPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final FloatCursor cursor = new FloatCursor(); + private int index; + + @Override + protected FloatCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationObjectIntHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectIntHashMap.java new file mode 100755 index 00000000..84b1aad2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectIntHashMap.java @@ -0,0 +1,447 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Comparator; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link ObjectIntHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link ObjectIntHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationObjectIntHashMap implements ObjectIntMap { + public final ObjectIntHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationObjectIntHashMap( + ObjectIntHashMap delegate, Comparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationObjectIntHashMap( + ObjectIntHashMap delegate, ObjectIntComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final KType[] keys = (KType[]) delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!(((KType) keys[keyIndex]) == null)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, Comparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + KType[] keys = (KType[]) delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, ObjectIntComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final KType[] keys = (KType[]) delegate.keys; + final int[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator> iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(KType key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(ObjectContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectIntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public > T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final KType[] keys = (KType[]) delegate.keys; + final int[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public > T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final KType[] keys = (KType[]) delegate.keys; + final int[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public ObjectCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public IntContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public int get(KType key) { + return delegate.get(key); + } + + @Override + public int getOrDefault(KType key, int defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public int put(KType key, int value) { + throw readOnlyException(); + } + + @Override + public int putAll(ObjectIntAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable> iterable) { + throw readOnlyException(); + } + + @Override + public int putOrAdd(KType key, int putValue, int incrementValue) { + throw readOnlyException(); + } + + @Override + public int addTo(KType key, int additionValue) { + throw readOnlyException(); + } + + @Override + public int remove(KType key) { + throw readOnlyException(); + } + + @Override + public int indexOf(KType key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public int indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public int indexReplace(int index, int newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, KType key, int value) { + throw readOnlyException(); + } + + @Override + public int indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final ObjectIntCursor cursor = new ObjectIntCursor(); + private int index; + + @Override + protected ObjectIntCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = (KType) delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractObjectCollection + implements ObjectLookupContainer { + private final SortedIterationObjectIntHashMap owner = + SortedIterationObjectIntHashMap.this; + + @Override + public boolean contains(KType e) { + return owner.containsKey(e); + } + + @Override + public > T forEach(final T procedure) { + owner.forEach((ObjectIntProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public > T forEach(final T predicate) { + owner.forEach((ObjectIntPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator> iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final KType e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator> { + private final ObjectCursor cursor = new ObjectCursor(); + private int index; + + @Override + protected ObjectCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = (KType) delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractIntCollection { + private final SortedIterationObjectIntHashMap owner = + SortedIterationObjectIntHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(int value) { + for (ObjectIntCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((ObjectIntProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((ObjectIntPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final int e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final IntCursor cursor = new IntCursor(); + private int index; + + @Override + protected IntCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationObjectLongHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectLongHashMap.java new file mode 100755 index 00000000..f353773c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectLongHashMap.java @@ -0,0 +1,447 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Comparator; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link ObjectLongHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link ObjectLongHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationObjectLongHashMap implements ObjectLongMap { + public final ObjectLongHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationObjectLongHashMap( + ObjectLongHashMap delegate, Comparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationObjectLongHashMap( + ObjectLongHashMap delegate, ObjectLongComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final KType[] keys = (KType[]) delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!(((KType) keys[keyIndex]) == null)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, Comparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + KType[] keys = (KType[]) delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, ObjectLongComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final KType[] keys = (KType[]) delegate.keys; + final long[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator> iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(KType key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(ObjectContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectLongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public > T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final KType[] keys = (KType[]) delegate.keys; + final long[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public > T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final KType[] keys = (KType[]) delegate.keys; + final long[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public ObjectCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public LongContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public long get(KType key) { + return delegate.get(key); + } + + @Override + public long getOrDefault(KType key, long defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public long put(KType key, long value) { + throw readOnlyException(); + } + + @Override + public int putAll(ObjectLongAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable> iterable) { + throw readOnlyException(); + } + + @Override + public long putOrAdd(KType key, long putValue, long incrementValue) { + throw readOnlyException(); + } + + @Override + public long addTo(KType key, long additionValue) { + throw readOnlyException(); + } + + @Override + public long remove(KType key) { + throw readOnlyException(); + } + + @Override + public int indexOf(KType key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public long indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public long indexReplace(int index, long newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, KType key, long value) { + throw readOnlyException(); + } + + @Override + public long indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final ObjectLongCursor cursor = new ObjectLongCursor(); + private int index; + + @Override + protected ObjectLongCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = (KType) delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractObjectCollection + implements ObjectLookupContainer { + private final SortedIterationObjectLongHashMap owner = + SortedIterationObjectLongHashMap.this; + + @Override + public boolean contains(KType e) { + return owner.containsKey(e); + } + + @Override + public > T forEach(final T procedure) { + owner.forEach((ObjectLongProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public > T forEach(final T predicate) { + owner.forEach((ObjectLongPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator> iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final KType e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator> { + private final ObjectCursor cursor = new ObjectCursor(); + private int index; + + @Override + protected ObjectCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = (KType) delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractLongCollection { + private final SortedIterationObjectLongHashMap owner = + SortedIterationObjectLongHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(long value) { + for (ObjectLongCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((ObjectLongProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((ObjectLongPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final long e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final LongCursor cursor = new LongCursor(); + private int index; + + @Override + protected LongCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationObjectObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectObjectHashMap.java new file mode 100755 index 00000000..d1c881be --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectObjectHashMap.java @@ -0,0 +1,440 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Comparator; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link ObjectObjectHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link ObjectObjectHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationObjectObjectHashMap + implements ObjectObjectMap { + public final ObjectObjectHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationObjectObjectHashMap( + ObjectObjectHashMap delegate, Comparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationObjectObjectHashMap( + ObjectObjectHashMap delegate, ObjectObjectComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final KType[] keys = (KType[]) delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!(((KType) keys[keyIndex]) == null)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, Comparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + KType[] keys = (KType[]) delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder( + int[] entryIndexes, ObjectObjectComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final KType[] keys = (KType[]) delegate.keys; + final VType[] values = (VType[]) delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator> iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(KType key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(ObjectContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public > T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final KType[] keys = (KType[]) delegate.keys; + final VType[] values = (VType[]) delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public > T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final KType[] keys = (KType[]) delegate.keys; + final VType[] values = (VType[]) delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public ObjectCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public ObjectContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public VType get(KType key) { + return delegate.get(key); + } + + @Override + public VType getOrDefault(KType key, VType defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public VType put(KType key, VType value) { + throw readOnlyException(); + } + + @Override + public int putAll(ObjectObjectAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll( + Iterable> iterable) { + throw readOnlyException(); + } + + @Override + public VType remove(KType key) { + throw readOnlyException(); + } + + @Override + public int indexOf(KType key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public VType indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public VType indexReplace(int index, VType newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, KType key, VType value) { + throw readOnlyException(); + } + + @Override + public VType indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final ObjectObjectCursor cursor = new ObjectObjectCursor(); + private int index; + + @Override + protected ObjectObjectCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = (KType) delegate.keys[slot]; + cursor.value = (VType) delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractObjectCollection + implements ObjectLookupContainer { + private final SortedIterationObjectObjectHashMap owner = + SortedIterationObjectObjectHashMap.this; + + @Override + public boolean contains(KType e) { + return owner.containsKey(e); + } + + @Override + public > T forEach(final T procedure) { + owner.forEach((ObjectObjectProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public > T forEach(final T predicate) { + owner.forEach((ObjectObjectPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator> iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final KType e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator> { + private final ObjectCursor cursor = new ObjectCursor(); + private int index; + + @Override + protected ObjectCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = (KType) delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractObjectCollection { + private final SortedIterationObjectObjectHashMap owner = + SortedIterationObjectObjectHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(VType value) { + for (ObjectObjectCursor c : owner) { + if (java.util.Objects.equals(value, c.value)) { + return true; + } + } + return false; + } + + @Override + public > T forEach(T procedure) { + owner.forEach((ObjectObjectProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public > T forEach(T predicate) { + owner.forEach((ObjectObjectPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator> iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final VType e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator> { + private final ObjectCursor cursor = new ObjectCursor(); + private int index; + + @Override + protected ObjectCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = (VType) delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationObjectShortHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectShortHashMap.java new file mode 100755 index 00000000..69e7bd7e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectShortHashMap.java @@ -0,0 +1,447 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Comparator; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link ObjectShortHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link ObjectShortHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationObjectShortHashMap implements ObjectShortMap { + public final ObjectShortHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationObjectShortHashMap( + ObjectShortHashMap delegate, Comparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationObjectShortHashMap( + ObjectShortHashMap delegate, ObjectShortComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final KType[] keys = (KType[]) delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!(((KType) keys[keyIndex]) == null)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, Comparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + KType[] keys = (KType[]) delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, ObjectShortComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final KType[] keys = (KType[]) delegate.keys; + final short[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator> iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(KType key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(ObjectContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public > T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final KType[] keys = (KType[]) delegate.keys; + final short[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public > T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final KType[] keys = (KType[]) delegate.keys; + final short[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public ObjectCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public ShortContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public short get(KType key) { + return delegate.get(key); + } + + @Override + public short getOrDefault(KType key, short defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public short put(KType key, short value) { + throw readOnlyException(); + } + + @Override + public int putAll(ObjectShortAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable> iterable) { + throw readOnlyException(); + } + + @Override + public short putOrAdd(KType key, short putValue, short incrementValue) { + throw readOnlyException(); + } + + @Override + public short addTo(KType key, short additionValue) { + throw readOnlyException(); + } + + @Override + public short remove(KType key) { + throw readOnlyException(); + } + + @Override + public int indexOf(KType key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public short indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public short indexReplace(int index, short newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, KType key, short value) { + throw readOnlyException(); + } + + @Override + public short indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final ObjectShortCursor cursor = new ObjectShortCursor(); + private int index; + + @Override + protected ObjectShortCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = (KType) delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractObjectCollection + implements ObjectLookupContainer { + private final SortedIterationObjectShortHashMap owner = + SortedIterationObjectShortHashMap.this; + + @Override + public boolean contains(KType e) { + return owner.containsKey(e); + } + + @Override + public > T forEach(final T procedure) { + owner.forEach((ObjectShortProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public > T forEach(final T predicate) { + owner.forEach((ObjectShortPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator> iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final KType e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator> { + private final ObjectCursor cursor = new ObjectCursor(); + private int index; + + @Override + protected ObjectCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = (KType) delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractShortCollection { + private final SortedIterationObjectShortHashMap owner = + SortedIterationObjectShortHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(short value) { + for (ObjectShortCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((ObjectShortProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((ObjectShortPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final short e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ShortCursor cursor = new ShortCursor(); + private int index; + + @Override + protected ShortCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationShortByteHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationShortByteHashMap.java new file mode 100755 index 00000000..478d3dec --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationShortByteHashMap.java @@ -0,0 +1,442 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link ShortByteHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link ShortByteHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationShortByteHashMap implements ShortByteMap { + public final ShortByteHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationShortByteHashMap(ShortByteHashMap delegate, ShortComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationShortByteHashMap( + ShortByteHashMap delegate, ShortByteComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final short[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, ShortComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + short[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, ShortByteComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final short[] keys = delegate.keys; + final byte[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(short key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(ShortContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortBytePredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final short[] keys = delegate.keys; + final byte[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final short[] keys = delegate.keys; + final byte[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public ShortCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public ByteContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public byte get(short key) { + return delegate.get(key); + } + + @Override + public byte getOrDefault(short key, byte defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public byte put(short key, byte value) { + throw readOnlyException(); + } + + @Override + public int putAll(ShortByteAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public byte putOrAdd(short key, byte putValue, byte incrementValue) { + throw readOnlyException(); + } + + @Override + public byte addTo(short key, byte additionValue) { + throw readOnlyException(); + } + + @Override + public byte remove(short key) { + throw readOnlyException(); + } + + @Override + public int indexOf(short key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public byte indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public byte indexReplace(int index, byte newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, short key, byte value) { + throw readOnlyException(); + } + + @Override + public byte indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final ShortByteCursor cursor = new ShortByteCursor(); + private int index; + + @Override + protected ShortByteCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractShortCollection + implements ShortLookupContainer { + private final SortedIterationShortByteHashMap owner = SortedIterationShortByteHashMap.this; + + @Override + public boolean contains(short e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((ShortByteProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((ShortBytePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final short e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final ShortCursor cursor = new ShortCursor(); + private int index; + + @Override + protected ShortCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractByteCollection { + private final SortedIterationShortByteHashMap owner = SortedIterationShortByteHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(byte value) { + for (ShortByteCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((ShortByteProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((ShortBytePredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final byte e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final BytePredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ByteCursor cursor = new ByteCursor(); + private int index; + + @Override + protected ByteCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationShortCharHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationShortCharHashMap.java new file mode 100755 index 00000000..3f4ad7df --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationShortCharHashMap.java @@ -0,0 +1,442 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link ShortCharHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link ShortCharHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationShortCharHashMap implements ShortCharMap { + public final ShortCharHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationShortCharHashMap(ShortCharHashMap delegate, ShortComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationShortCharHashMap( + ShortCharHashMap delegate, ShortCharComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final short[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, ShortComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + short[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, ShortCharComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final short[] keys = delegate.keys; + final char[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(short key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(ShortContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortCharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final short[] keys = delegate.keys; + final char[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final short[] keys = delegate.keys; + final char[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public ShortCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public CharContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public char get(short key) { + return delegate.get(key); + } + + @Override + public char getOrDefault(short key, char defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public char put(short key, char value) { + throw readOnlyException(); + } + + @Override + public int putAll(ShortCharAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public char putOrAdd(short key, char putValue, char incrementValue) { + throw readOnlyException(); + } + + @Override + public char addTo(short key, char additionValue) { + throw readOnlyException(); + } + + @Override + public char remove(short key) { + throw readOnlyException(); + } + + @Override + public int indexOf(short key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public char indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public char indexReplace(int index, char newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, short key, char value) { + throw readOnlyException(); + } + + @Override + public char indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final ShortCharCursor cursor = new ShortCharCursor(); + private int index; + + @Override + protected ShortCharCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractShortCollection + implements ShortLookupContainer { + private final SortedIterationShortCharHashMap owner = SortedIterationShortCharHashMap.this; + + @Override + public boolean contains(short e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((ShortCharProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((ShortCharPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final short e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final ShortCursor cursor = new ShortCursor(); + private int index; + + @Override + protected ShortCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractCharCollection { + private final SortedIterationShortCharHashMap owner = SortedIterationShortCharHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(char value) { + for (ShortCharCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((ShortCharProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((ShortCharPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final char e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final CharPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final CharCursor cursor = new CharCursor(); + private int index; + + @Override + protected CharCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationShortDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationShortDoubleHashMap.java new file mode 100755 index 00000000..a9ae3265 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationShortDoubleHashMap.java @@ -0,0 +1,443 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link ShortDoubleHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link ShortDoubleHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationShortDoubleHashMap implements ShortDoubleMap { + public final ShortDoubleHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationShortDoubleHashMap( + ShortDoubleHashMap delegate, ShortComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationShortDoubleHashMap( + ShortDoubleHashMap delegate, ShortDoubleComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final short[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, ShortComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + short[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, ShortDoubleComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final short[] keys = delegate.keys; + final double[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(short key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(ShortContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortDoublePredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final short[] keys = delegate.keys; + final double[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final short[] keys = delegate.keys; + final double[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public ShortCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public DoubleContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public double get(short key) { + return delegate.get(key); + } + + @Override + public double getOrDefault(short key, double defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public double put(short key, double value) { + throw readOnlyException(); + } + + @Override + public int putAll(ShortDoubleAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public double putOrAdd(short key, double putValue, double incrementValue) { + throw readOnlyException(); + } + + @Override + public double addTo(short key, double additionValue) { + throw readOnlyException(); + } + + @Override + public double remove(short key) { + throw readOnlyException(); + } + + @Override + public int indexOf(short key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public double indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public double indexReplace(int index, double newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, short key, double value) { + throw readOnlyException(); + } + + @Override + public double indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final ShortDoubleCursor cursor = new ShortDoubleCursor(); + private int index; + + @Override + protected ShortDoubleCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractShortCollection + implements ShortLookupContainer { + private final SortedIterationShortDoubleHashMap owner = SortedIterationShortDoubleHashMap.this; + + @Override + public boolean contains(short e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((ShortDoubleProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((ShortDoublePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final short e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final ShortCursor cursor = new ShortCursor(); + private int index; + + @Override + protected ShortCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractDoubleCollection { + private final SortedIterationShortDoubleHashMap owner = SortedIterationShortDoubleHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(double value) { + for (ShortDoubleCursor c : owner) { + if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((ShortDoubleProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((ShortDoublePredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final double e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final DoublePredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final DoubleCursor cursor = new DoubleCursor(); + private int index; + + @Override + protected DoubleCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationShortFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationShortFloatHashMap.java new file mode 100755 index 00000000..bad3ad03 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationShortFloatHashMap.java @@ -0,0 +1,442 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link ShortFloatHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link ShortFloatHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationShortFloatHashMap implements ShortFloatMap { + public final ShortFloatHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationShortFloatHashMap(ShortFloatHashMap delegate, ShortComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationShortFloatHashMap( + ShortFloatHashMap delegate, ShortFloatComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final short[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, ShortComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + short[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, ShortFloatComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final short[] keys = delegate.keys; + final float[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(short key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(ShortContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortFloatPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final short[] keys = delegate.keys; + final float[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final short[] keys = delegate.keys; + final float[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public ShortCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public FloatContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public float get(short key) { + return delegate.get(key); + } + + @Override + public float getOrDefault(short key, float defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public float put(short key, float value) { + throw readOnlyException(); + } + + @Override + public int putAll(ShortFloatAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public float putOrAdd(short key, float putValue, float incrementValue) { + throw readOnlyException(); + } + + @Override + public float addTo(short key, float additionValue) { + throw readOnlyException(); + } + + @Override + public float remove(short key) { + throw readOnlyException(); + } + + @Override + public int indexOf(short key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public float indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public float indexReplace(int index, float newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, short key, float value) { + throw readOnlyException(); + } + + @Override + public float indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final ShortFloatCursor cursor = new ShortFloatCursor(); + private int index; + + @Override + protected ShortFloatCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractShortCollection + implements ShortLookupContainer { + private final SortedIterationShortFloatHashMap owner = SortedIterationShortFloatHashMap.this; + + @Override + public boolean contains(short e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((ShortFloatProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((ShortFloatPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final short e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final ShortCursor cursor = new ShortCursor(); + private int index; + + @Override + protected ShortCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractFloatCollection { + private final SortedIterationShortFloatHashMap owner = SortedIterationShortFloatHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(float value) { + for (ShortFloatCursor c : owner) { + if ((Float.floatToIntBits(value) == Float.floatToIntBits(c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((ShortFloatProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((ShortFloatPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final float e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final FloatPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final FloatCursor cursor = new FloatCursor(); + private int index; + + @Override + protected FloatCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationShortIntHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationShortIntHashMap.java new file mode 100755 index 00000000..501b0a07 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationShortIntHashMap.java @@ -0,0 +1,441 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link ShortIntHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link ShortIntHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationShortIntHashMap implements ShortIntMap { + public final ShortIntHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationShortIntHashMap(ShortIntHashMap delegate, ShortComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationShortIntHashMap(ShortIntHashMap delegate, ShortIntComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final short[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, ShortComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + short[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, ShortIntComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final short[] keys = delegate.keys; + final int[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(short key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(ShortContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortIntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final short[] keys = delegate.keys; + final int[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final short[] keys = delegate.keys; + final int[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public ShortCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public IntContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public int get(short key) { + return delegate.get(key); + } + + @Override + public int getOrDefault(short key, int defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public int put(short key, int value) { + throw readOnlyException(); + } + + @Override + public int putAll(ShortIntAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public int putOrAdd(short key, int putValue, int incrementValue) { + throw readOnlyException(); + } + + @Override + public int addTo(short key, int additionValue) { + throw readOnlyException(); + } + + @Override + public int remove(short key) { + throw readOnlyException(); + } + + @Override + public int indexOf(short key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public int indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public int indexReplace(int index, int newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, short key, int value) { + throw readOnlyException(); + } + + @Override + public int indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final ShortIntCursor cursor = new ShortIntCursor(); + private int index; + + @Override + protected ShortIntCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractShortCollection + implements ShortLookupContainer { + private final SortedIterationShortIntHashMap owner = SortedIterationShortIntHashMap.this; + + @Override + public boolean contains(short e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((ShortIntProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((ShortIntPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final short e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final ShortCursor cursor = new ShortCursor(); + private int index; + + @Override + protected ShortCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractIntCollection { + private final SortedIterationShortIntHashMap owner = SortedIterationShortIntHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(int value) { + for (ShortIntCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((ShortIntProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((ShortIntPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final int e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final IntPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final IntCursor cursor = new IntCursor(); + private int index; + + @Override + protected IntCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationShortLongHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationShortLongHashMap.java new file mode 100755 index 00000000..5aae2e1f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationShortLongHashMap.java @@ -0,0 +1,442 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link ShortLongHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link ShortLongHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationShortLongHashMap implements ShortLongMap { + public final ShortLongHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationShortLongHashMap(ShortLongHashMap delegate, ShortComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationShortLongHashMap( + ShortLongHashMap delegate, ShortLongComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final short[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, ShortComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + short[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, ShortLongComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final short[] keys = delegate.keys; + final long[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(short key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(ShortContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortLongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final short[] keys = delegate.keys; + final long[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final short[] keys = delegate.keys; + final long[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public ShortCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public LongContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public long get(short key) { + return delegate.get(key); + } + + @Override + public long getOrDefault(short key, long defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public long put(short key, long value) { + throw readOnlyException(); + } + + @Override + public int putAll(ShortLongAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public long putOrAdd(short key, long putValue, long incrementValue) { + throw readOnlyException(); + } + + @Override + public long addTo(short key, long additionValue) { + throw readOnlyException(); + } + + @Override + public long remove(short key) { + throw readOnlyException(); + } + + @Override + public int indexOf(short key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public long indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public long indexReplace(int index, long newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, short key, long value) { + throw readOnlyException(); + } + + @Override + public long indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final ShortLongCursor cursor = new ShortLongCursor(); + private int index; + + @Override + protected ShortLongCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractShortCollection + implements ShortLookupContainer { + private final SortedIterationShortLongHashMap owner = SortedIterationShortLongHashMap.this; + + @Override + public boolean contains(short e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((ShortLongProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((ShortLongPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final short e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final ShortCursor cursor = new ShortCursor(); + private int index; + + @Override + protected ShortCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractLongCollection { + private final SortedIterationShortLongHashMap owner = SortedIterationShortLongHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(long value) { + for (ShortLongCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((ShortLongProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((ShortLongPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final long e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final LongPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final LongCursor cursor = new LongCursor(); + private int index; + + @Override + protected LongCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationShortObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationShortObjectHashMap.java new file mode 100755 index 00000000..989690ae --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationShortObjectHashMap.java @@ -0,0 +1,436 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link ShortObjectHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link ShortObjectHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@SuppressWarnings("unchecked") +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationShortObjectHashMap implements ShortObjectMap { + public final ShortObjectHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationShortObjectHashMap( + ShortObjectHashMap delegate, ShortComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationShortObjectHashMap( + ShortObjectHashMap delegate, ShortObjectComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final short[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, ShortComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + short[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, ShortObjectComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final short[] keys = delegate.keys; + final VType[] values = (VType[]) delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator> iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(short key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(ShortContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public > T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final short[] keys = delegate.keys; + final VType[] values = (VType[]) delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public > T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final short[] keys = delegate.keys; + final VType[] values = (VType[]) delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public ShortCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public ObjectContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public VType get(short key) { + return delegate.get(key); + } + + @Override + public VType getOrDefault(short key, VType defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public VType put(short key, VType value) { + throw readOnlyException(); + } + + @Override + public int putAll(ShortObjectAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable> iterable) { + throw readOnlyException(); + } + + @Override + public VType remove(short key) { + throw readOnlyException(); + } + + @Override + public int indexOf(short key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public VType indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public VType indexReplace(int index, VType newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, short key, VType value) { + throw readOnlyException(); + } + + @Override + public VType indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator> { + private final ShortObjectCursor cursor = new ShortObjectCursor(); + private int index; + + @Override + protected ShortObjectCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = (VType) delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractShortCollection + implements ShortLookupContainer { + private final SortedIterationShortObjectHashMap owner = + SortedIterationShortObjectHashMap.this; + + @Override + public boolean contains(short e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((ShortObjectProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((ShortObjectPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final short e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final ShortCursor cursor = new ShortCursor(); + private int index; + + @Override + protected ShortCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractObjectCollection { + private final SortedIterationShortObjectHashMap owner = + SortedIterationShortObjectHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(VType value) { + for (ShortObjectCursor c : owner) { + if (java.util.Objects.equals(value, c.value)) { + return true; + } + } + return false; + } + + @Override + public > T forEach(T procedure) { + owner.forEach((ShortObjectProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public > T forEach(T predicate) { + owner.forEach((ShortObjectPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator> iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final VType e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final ObjectPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator> { + private final ObjectCursor cursor = new ObjectCursor(); + private int index; + + @Override + protected ObjectCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = (VType) delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/SortedIterationShortShortHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationShortShortHashMap.java new file mode 100755 index 00000000..d7266230 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationShortShortHashMap.java @@ -0,0 +1,442 @@ +package com.carrotsearch.hppc; + +import com.carrotsearch.hppc.comparators.*; +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import com.carrotsearch.hppc.sorting.QuickSort; +import java.util.Iterator; +import java.util.function.IntBinaryOperator; + +/** + * Read-only view with sorted iteration order on a delegate {@link ShortShortHashMap}. + * + *

In its constructor, this view creates its own iteration order array and sorts it, which is in + * O(n.log(n)) of the size of the delegate map. Afterward, calls to any method have the same + * performance as the delegate map. + * + *

This view is read-only. In addition, the delegate map must not be modified while the view is + * used, otherwise the iteration is undefined. + * + *

Since this view provides a fixed iteration order, it must not be used to add entries to + * another {@link ShortShortHashMap} as this may result in a runtime deadlock. See HPPC-103 and HPPC-186 for more information. + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "SortedIterationKTypeVTypeHashMap.java") +public class SortedIterationShortShortHashMap implements ShortShortMap { + public final ShortShortHashMap delegate; + public final int[] iterationOrder; + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on the keys. + */ + public SortedIterationShortShortHashMap(ShortShortHashMap delegate, ShortComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + /** + * Creates a read-only view with sorted iteration order on the given delegate map. The ordering is + * based on the provided comparator on keys and values. + */ + public SortedIterationShortShortHashMap( + ShortShortHashMap delegate, ShortShortComparator comparator) { + this.delegate = delegate; + this.iterationOrder = sortIterationOrder(createEntryIndexes(), comparator); + } + + private int[] createEntryIndexes() { + final short[] keys = delegate.keys; + final int size = delegate.size(); + int[] entryIndexes = new int[size]; + int entry = 0; + if (delegate.hasEmptyKey) { + entryIndexes[entry++] = delegate.mask + 1; + } + for (int keyIndex = 0; entry < size; keyIndex++) { + if (!((keys[keyIndex]) == 0)) { + entryIndexes[entry++] = keyIndex; + } + } + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on the keys. */ + protected int[] sortIterationOrder(int[] entryIndexes, ShortComparator comparator) { + QuickSort.sort( + entryIndexes, + (i, j) -> { + short[] keys = delegate.keys; + return comparator.compare(keys[entryIndexes[i]], keys[entryIndexes[j]]); + }); + return entryIndexes; + } + + /** Sort the iteration order array based on the provided comparator on keys and values. */ + protected int[] sortIterationOrder(int[] entryIndexes, ShortShortComparator comparator) { + QuickSort.sort( + entryIndexes, + new IntBinaryOperator() { + final short[] keys = delegate.keys; + final short[] values = delegate.values; + + @Override + public int applyAsInt(int i, int j) { + int index1 = entryIndexes[i]; + int index2 = entryIndexes[j]; + return comparator.compare(keys[index1], values[index1], keys[index2], values[index2]); + } + }); + return entryIndexes; + } + + @Override + public Iterator iterator() { + assert checkUnmodified(); + return new EntryIterator(); + } + + @Override + public boolean containsKey(short key) { + return delegate.containsKey(key); + } + + @Override + public int size() { + assert checkUnmodified(); + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public int removeAll(ShortContainer container) { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public T forEach(T procedure) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final short[] keys = delegate.keys; + final short[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + procedure.apply(keys[slot], values[slot]); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + assert checkUnmodified(); + final int[] iterationOrder = this.iterationOrder; + final short[] keys = delegate.keys; + final short[] values = delegate.values; + for (int i = 0, size = size(); i < size; i++) { + int slot = iterationOrder[i]; + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + return predicate; + } + + @Override + public ShortCollection keys() { + assert checkUnmodified(); + return new KeysContainer(); + } + + @Override + public ShortContainer values() { + assert checkUnmodified(); + return new ValuesContainer(); + } + + @Override + public short get(short key) { + return delegate.get(key); + } + + @Override + public short getOrDefault(short key, short defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public short put(short key, short value) { + throw readOnlyException(); + } + + @Override + public int putAll(ShortShortAssociativeContainer container) { + throw readOnlyException(); + } + + @Override + public int putAll(Iterable iterable) { + throw readOnlyException(); + } + + @Override + public short putOrAdd(short key, short putValue, short incrementValue) { + throw readOnlyException(); + } + + @Override + public short addTo(short key, short additionValue) { + throw readOnlyException(); + } + + @Override + public short remove(short key) { + throw readOnlyException(); + } + + @Override + public int indexOf(short key) { + return delegate.indexOf(key); + } + + @Override + public boolean indexExists(int index) { + return delegate.indexExists(index); + } + + @Override + public short indexGet(int index) { + return delegate.indexGet(index); + } + + @Override + public short indexReplace(int index, short newValue) { + throw readOnlyException(); + } + + @Override + public void indexInsert(int index, short key, short value) { + throw readOnlyException(); + } + + @Override + public short indexRemove(int index) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return delegate.visualizeKeyDistribution(characters); + } + + private static RuntimeException readOnlyException() { + throw new UnsupportedOperationException("Read-only view cannot be modified"); + } + + private boolean checkUnmodified() { + // Cheap size comparison. + // We could also check the hashcode, but this is heavy for a frequent check. + assert delegate.size() == iterationOrder.length + : "The delegate map changed; this is not supported by this read-only view"; + return true; + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final ShortShortCursor cursor = new ShortShortCursor(); + private int index; + + @Override + protected ShortShortCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.key = delegate.keys[slot]; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the keys in sorted order. */ + private final class KeysContainer extends AbstractShortCollection + implements ShortLookupContainer { + private final SortedIterationShortShortHashMap owner = SortedIterationShortShortHashMap.this; + + @Override + public boolean contains(short e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((ShortShortProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((ShortShortPredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + + @Override + public int removeAll(ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public int removeAll(final short e) { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final ShortCursor cursor = new ShortCursor(); + private int index; + + @Override + protected ShortCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.keys[slot]; + return cursor; + } + return done(); + } + } + + /** A view of the values in sorted order. */ + private final class ValuesContainer extends AbstractShortCollection { + private final SortedIterationShortShortHashMap owner = SortedIterationShortShortHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(short value) { + for (ShortShortCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + owner.forEach((ShortShortProcedure) (k, v) -> procedure.apply(v)); + return procedure; + } + + @Override + public T forEach(T predicate) { + owner.forEach((ShortShortPredicate) (k, v) -> predicate.apply(v)); + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final short e) { + throw readOnlyException(); + } + + @Override + public int removeAll(final ShortPredicate predicate) { + throw readOnlyException(); + } + + @Override + public void clear() { + throw readOnlyException(); + } + + @Override + public void release() { + throw readOnlyException(); + } + } + + /** A sorted iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ShortCursor cursor = new ShortCursor(); + private int index; + + @Override + protected ShortCursor fetch() { + if (index < iterationOrder.length) { + int slot = iterationOrder[index++]; + cursor.index = slot; + cursor.value = delegate.values[slot]; + return cursor; + } + return done(); + } + } +} diff --git a/src/main/java/com/carrotsearch/hppc/XorShift128P.java b/src/main/java/com/carrotsearch/hppc/XorShift128P.java new file mode 100755 index 00000000..e9db0a0d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/XorShift128P.java @@ -0,0 +1,67 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc; + +import java.util.Random; + +/** + * A fast pseudo-random number generator. For simplicity, we do not implement all of {@link Random} + * methods. + * + * @see "https://xorshift.di.unimi.it/" + * @see "https://xorshift.di.unimi.it/xorshift128plus.c" + */ +public class XorShift128P { + /* + * 128 bits of state. + */ + private long state0, state1; + + public XorShift128P(long seed) { + state0 = notZero(BitMixer.mix64(seed)); + state1 = notZero(BitMixer.mix64(seed + 1)); + } + + public XorShift128P() { + this(Containers.randomSeed64()); + } + + public long nextLong() { + long s1 = state0; + long s0 = state1; + state0 = s0; + s1 ^= s1 << 23; + return (state1 = (s1 ^ s0 ^ (s1 >>> 17) ^ (s0 >>> 26))) + s0; + } + + public int nextInt() { + return (int) nextLong(); + } + + private static long notZero(long value) { + return value == 0 ? 0xdeadbeefbabeL : value; + } + + public int nextInt(int bound) { + if (bound <= 0) { + throw new IllegalArgumentException(); + } + + int r = (nextInt() >>> 1); + int m = bound - 1; + if ((bound & m) == 0) { + r = (int) ((bound * (long) r) >> 31); + } else { + for (int u = r; u - (r = u % bound) + m < 0; u = nextInt() >>> 1) {} + } + + return r; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ByteByteComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ByteByteComparator.java new file mode 100755 index 00000000..734e028b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ByteByteComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two byte, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ByteByteComparator { + int compare(byte k1, byte v1, byte k2, byte v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ByteCharComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ByteCharComparator.java new file mode 100755 index 00000000..6682edd4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ByteCharComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two byte, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ByteCharComparator { + int compare(byte k1, char v1, byte k2, char v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ByteComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ByteComparator.java new file mode 100755 index 00000000..0ff9f381 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ByteComparator.java @@ -0,0 +1,11 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two byte values. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeComparator.java") +public interface ByteComparator { + int compare(byte a, byte b); + + static ByteComparator naturalOrder() { + return Byte::compare; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ByteDoubleComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ByteDoubleComparator.java new file mode 100755 index 00000000..84b6105f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ByteDoubleComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two byte, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ByteDoubleComparator { + int compare(byte k1, double v1, byte k2, double v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ByteFloatComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ByteFloatComparator.java new file mode 100755 index 00000000..a54901d6 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ByteFloatComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two byte, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ByteFloatComparator { + int compare(byte k1, float v1, byte k2, float v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ByteIntComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ByteIntComparator.java new file mode 100755 index 00000000..e2fed664 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ByteIntComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two byte, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ByteIntComparator { + int compare(byte k1, int v1, byte k2, int v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ByteLongComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ByteLongComparator.java new file mode 100755 index 00000000..5684a8bc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ByteLongComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two byte, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ByteLongComparator { + int compare(byte k1, long v1, byte k2, long v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ByteObjectComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ByteObjectComparator.java new file mode 100755 index 00000000..fc1c19a8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ByteObjectComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two byte, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ByteObjectComparator { + int compare(byte k1, VType v1, byte k2, VType v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ByteShortComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ByteShortComparator.java new file mode 100755 index 00000000..154a2167 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ByteShortComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two byte, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ByteShortComparator { + int compare(byte k1, short v1, byte k2, short v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/CharByteComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/CharByteComparator.java new file mode 100755 index 00000000..807f0e0c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/CharByteComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two char, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface CharByteComparator { + int compare(char k1, byte v1, char k2, byte v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/CharCharComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/CharCharComparator.java new file mode 100755 index 00000000..0f790620 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/CharCharComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two char, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface CharCharComparator { + int compare(char k1, char v1, char k2, char v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/CharComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/CharComparator.java new file mode 100755 index 00000000..acedac68 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/CharComparator.java @@ -0,0 +1,11 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two char values. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeComparator.java") +public interface CharComparator { + int compare(char a, char b); + + static CharComparator naturalOrder() { + return Character::compare; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/CharDoubleComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/CharDoubleComparator.java new file mode 100755 index 00000000..486620ca --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/CharDoubleComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two char, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface CharDoubleComparator { + int compare(char k1, double v1, char k2, double v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/CharFloatComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/CharFloatComparator.java new file mode 100755 index 00000000..47bc5950 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/CharFloatComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two char, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface CharFloatComparator { + int compare(char k1, float v1, char k2, float v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/CharIntComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/CharIntComparator.java new file mode 100755 index 00000000..c2a225d4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/CharIntComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two char, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface CharIntComparator { + int compare(char k1, int v1, char k2, int v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/CharLongComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/CharLongComparator.java new file mode 100755 index 00000000..390998ec --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/CharLongComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two char, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface CharLongComparator { + int compare(char k1, long v1, char k2, long v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/CharObjectComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/CharObjectComparator.java new file mode 100755 index 00000000..fdab147d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/CharObjectComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two char, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface CharObjectComparator { + int compare(char k1, VType v1, char k2, VType v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/CharShortComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/CharShortComparator.java new file mode 100755 index 00000000..91ba9976 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/CharShortComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two char, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface CharShortComparator { + int compare(char k1, short v1, char k2, short v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/DoubleByteComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/DoubleByteComparator.java new file mode 100755 index 00000000..60fae03f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/DoubleByteComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two double, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface DoubleByteComparator { + int compare(double k1, byte v1, double k2, byte v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/DoubleCharComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/DoubleCharComparator.java new file mode 100755 index 00000000..ec215c93 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/DoubleCharComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two double, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface DoubleCharComparator { + int compare(double k1, char v1, double k2, char v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/DoubleComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/DoubleComparator.java new file mode 100755 index 00000000..193b5f90 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/DoubleComparator.java @@ -0,0 +1,7 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two double values. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeComparator.java") +public interface DoubleComparator { + int compare(double a, double b); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/DoubleDoubleComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/DoubleDoubleComparator.java new file mode 100755 index 00000000..20ba2dcc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/DoubleDoubleComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two double, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface DoubleDoubleComparator { + int compare(double k1, double v1, double k2, double v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/DoubleFloatComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/DoubleFloatComparator.java new file mode 100755 index 00000000..50aca950 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/DoubleFloatComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two double, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface DoubleFloatComparator { + int compare(double k1, float v1, double k2, float v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/DoubleIntComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/DoubleIntComparator.java new file mode 100755 index 00000000..afd12514 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/DoubleIntComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two double, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface DoubleIntComparator { + int compare(double k1, int v1, double k2, int v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/DoubleLongComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/DoubleLongComparator.java new file mode 100755 index 00000000..a843ec6a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/DoubleLongComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two double, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface DoubleLongComparator { + int compare(double k1, long v1, double k2, long v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/DoubleObjectComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/DoubleObjectComparator.java new file mode 100755 index 00000000..9d654aab --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/DoubleObjectComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two double, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface DoubleObjectComparator { + int compare(double k1, VType v1, double k2, VType v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/DoubleShortComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/DoubleShortComparator.java new file mode 100755 index 00000000..4b463161 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/DoubleShortComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two double, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface DoubleShortComparator { + int compare(double k1, short v1, double k2, short v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/FloatByteComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/FloatByteComparator.java new file mode 100755 index 00000000..298f94b0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/FloatByteComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two float, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface FloatByteComparator { + int compare(float k1, byte v1, float k2, byte v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/FloatCharComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/FloatCharComparator.java new file mode 100755 index 00000000..a2af271b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/FloatCharComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two float, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface FloatCharComparator { + int compare(float k1, char v1, float k2, char v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/FloatComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/FloatComparator.java new file mode 100755 index 00000000..8831a3bc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/FloatComparator.java @@ -0,0 +1,7 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two float values. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeComparator.java") +public interface FloatComparator { + int compare(float a, float b); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/FloatDoubleComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/FloatDoubleComparator.java new file mode 100755 index 00000000..26cfcb64 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/FloatDoubleComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two float, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface FloatDoubleComparator { + int compare(float k1, double v1, float k2, double v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/FloatFloatComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/FloatFloatComparator.java new file mode 100755 index 00000000..8fc373bb --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/FloatFloatComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two float, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface FloatFloatComparator { + int compare(float k1, float v1, float k2, float v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/FloatIntComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/FloatIntComparator.java new file mode 100755 index 00000000..86199e53 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/FloatIntComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two float, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface FloatIntComparator { + int compare(float k1, int v1, float k2, int v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/FloatLongComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/FloatLongComparator.java new file mode 100755 index 00000000..7dcc9e44 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/FloatLongComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two float, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface FloatLongComparator { + int compare(float k1, long v1, float k2, long v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/FloatObjectComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/FloatObjectComparator.java new file mode 100755 index 00000000..f1e9cd64 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/FloatObjectComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two float, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface FloatObjectComparator { + int compare(float k1, VType v1, float k2, VType v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/FloatShortComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/FloatShortComparator.java new file mode 100755 index 00000000..baac7d4f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/FloatShortComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two float, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface FloatShortComparator { + int compare(float k1, short v1, float k2, short v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/IntByteComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/IntByteComparator.java new file mode 100755 index 00000000..fe34ad58 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/IntByteComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two int, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface IntByteComparator { + int compare(int k1, byte v1, int k2, byte v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/IntCharComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/IntCharComparator.java new file mode 100755 index 00000000..b682c529 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/IntCharComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two int, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface IntCharComparator { + int compare(int k1, char v1, int k2, char v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/IntComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/IntComparator.java new file mode 100755 index 00000000..3501d91a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/IntComparator.java @@ -0,0 +1,11 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two int values. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeComparator.java") +public interface IntComparator { + int compare(int a, int b); + + static IntComparator naturalOrder() { + return Integer::compare; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/IntDoubleComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/IntDoubleComparator.java new file mode 100755 index 00000000..5d6580d9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/IntDoubleComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two int, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface IntDoubleComparator { + int compare(int k1, double v1, int k2, double v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/IntFloatComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/IntFloatComparator.java new file mode 100755 index 00000000..6cb79069 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/IntFloatComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two int, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface IntFloatComparator { + int compare(int k1, float v1, int k2, float v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/IntIntComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/IntIntComparator.java new file mode 100755 index 00000000..fe4214fc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/IntIntComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two int, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface IntIntComparator { + int compare(int k1, int v1, int k2, int v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/IntLongComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/IntLongComparator.java new file mode 100755 index 00000000..620a6978 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/IntLongComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two int, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface IntLongComparator { + int compare(int k1, long v1, int k2, long v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/IntObjectComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/IntObjectComparator.java new file mode 100755 index 00000000..8fbbb04c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/IntObjectComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two int, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface IntObjectComparator { + int compare(int k1, VType v1, int k2, VType v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/IntShortComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/IntShortComparator.java new file mode 100755 index 00000000..5657bdb0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/IntShortComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two int, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface IntShortComparator { + int compare(int k1, short v1, int k2, short v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/LongByteComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/LongByteComparator.java new file mode 100755 index 00000000..326d0f1c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/LongByteComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two long, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface LongByteComparator { + int compare(long k1, byte v1, long k2, byte v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/LongCharComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/LongCharComparator.java new file mode 100755 index 00000000..7c2267f5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/LongCharComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two long, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface LongCharComparator { + int compare(long k1, char v1, long k2, char v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/LongComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/LongComparator.java new file mode 100755 index 00000000..d090607c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/LongComparator.java @@ -0,0 +1,11 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two long values. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeComparator.java") +public interface LongComparator { + int compare(long a, long b); + + static LongComparator naturalOrder() { + return Long::compare; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/LongDoubleComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/LongDoubleComparator.java new file mode 100755 index 00000000..25f39e20 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/LongDoubleComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two long, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface LongDoubleComparator { + int compare(long k1, double v1, long k2, double v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/LongFloatComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/LongFloatComparator.java new file mode 100755 index 00000000..dde992f6 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/LongFloatComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two long, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface LongFloatComparator { + int compare(long k1, float v1, long k2, float v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/LongIntComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/LongIntComparator.java new file mode 100755 index 00000000..de63af1d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/LongIntComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two long, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface LongIntComparator { + int compare(long k1, int v1, long k2, int v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/LongLongComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/LongLongComparator.java new file mode 100755 index 00000000..9b0822d8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/LongLongComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two long, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface LongLongComparator { + int compare(long k1, long v1, long k2, long v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/LongObjectComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/LongObjectComparator.java new file mode 100755 index 00000000..42fd64ba --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/LongObjectComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two long, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface LongObjectComparator { + int compare(long k1, VType v1, long k2, VType v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/LongShortComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/LongShortComparator.java new file mode 100755 index 00000000..b6377dd2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/LongShortComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two long, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface LongShortComparator { + int compare(long k1, short v1, long k2, short v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ObjectByteComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ObjectByteComparator.java new file mode 100755 index 00000000..54d86da0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ObjectByteComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two Object, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ObjectByteComparator { + int compare(KType k1, byte v1, KType k2, byte v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ObjectCharComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ObjectCharComparator.java new file mode 100755 index 00000000..0c8f42dc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ObjectCharComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two Object, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ObjectCharComparator { + int compare(KType k1, char v1, KType k2, char v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ObjectDoubleComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ObjectDoubleComparator.java new file mode 100755 index 00000000..1ec17275 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ObjectDoubleComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two Object, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ObjectDoubleComparator { + int compare(KType k1, double v1, KType k2, double v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ObjectFloatComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ObjectFloatComparator.java new file mode 100755 index 00000000..1c289f20 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ObjectFloatComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two Object, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ObjectFloatComparator { + int compare(KType k1, float v1, KType k2, float v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ObjectIntComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ObjectIntComparator.java new file mode 100755 index 00000000..fe143279 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ObjectIntComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two Object, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ObjectIntComparator { + int compare(KType k1, int v1, KType k2, int v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ObjectLongComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ObjectLongComparator.java new file mode 100755 index 00000000..e031f4ea --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ObjectLongComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two Object, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ObjectLongComparator { + int compare(KType k1, long v1, KType k2, long v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ObjectObjectComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ObjectObjectComparator.java new file mode 100755 index 00000000..ed5a2d68 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ObjectObjectComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two Object, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ObjectObjectComparator { + int compare(KType k1, VType v1, KType k2, VType v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ObjectShortComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ObjectShortComparator.java new file mode 100755 index 00000000..c545a557 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ObjectShortComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two Object, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ObjectShortComparator { + int compare(KType k1, short v1, KType k2, short v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ShortByteComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ShortByteComparator.java new file mode 100755 index 00000000..b372f942 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ShortByteComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two short, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ShortByteComparator { + int compare(short k1, byte v1, short k2, byte v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ShortCharComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ShortCharComparator.java new file mode 100755 index 00000000..82b9b0a3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ShortCharComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two short, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ShortCharComparator { + int compare(short k1, char v1, short k2, char v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ShortComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ShortComparator.java new file mode 100755 index 00000000..b935f60b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ShortComparator.java @@ -0,0 +1,11 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two short values. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeComparator.java") +public interface ShortComparator { + int compare(short a, short b); + + static ShortComparator naturalOrder() { + return Short::compare; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ShortDoubleComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ShortDoubleComparator.java new file mode 100755 index 00000000..37c2a7b5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ShortDoubleComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two short, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ShortDoubleComparator { + int compare(short k1, double v1, short k2, double v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ShortFloatComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ShortFloatComparator.java new file mode 100755 index 00000000..15eec4a8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ShortFloatComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two short, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ShortFloatComparator { + int compare(short k1, float v1, short k2, float v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ShortIntComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ShortIntComparator.java new file mode 100755 index 00000000..9d5ad1fe --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ShortIntComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two short, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ShortIntComparator { + int compare(short k1, int v1, short k2, int v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ShortLongComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ShortLongComparator.java new file mode 100755 index 00000000..9e394e1a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ShortLongComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two short, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ShortLongComparator { + int compare(short k1, long v1, short k2, long v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ShortObjectComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ShortObjectComparator.java new file mode 100755 index 00000000..6d1715f3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ShortObjectComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two short, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ShortObjectComparator { + int compare(short k1, VType v1, short k2, VType v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/comparators/ShortShortComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ShortShortComparator.java new file mode 100755 index 00000000..ccd78621 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ShortShortComparator.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.comparators; + +/** Compares two short, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:17+0200", + value = "KTypeVTypeComparator.java") +public interface ShortShortComparator { + int compare(short k1, short v1, short k2, short v2); +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ByteCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ByteCursor.java new file mode 100755 index 00000000..e0b695dd --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ByteCursor.java @@ -0,0 +1,19 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over a collection of bytes. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCursor.java") +public final class ByteCursor { + /** + * The current value's index in the container this cursor belongs to. The meaning of this index is + * defined by the container (usually it will be an index in the underlying storage buffer). + */ + public int index; + + /** The current value. */ + public byte value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/CharByteCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/CharByteCursor.java new file mode 100755 index 00000000..9e36f8f1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/CharByteCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (char keys and byte values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class CharByteCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public char key; + + /** The current value. */ + public byte value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/CharCharCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/CharCharCursor.java new file mode 100755 index 00000000..079a2682 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/CharCharCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (char keys and char values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class CharCharCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public char key; + + /** The current value. */ + public char value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/CharCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/CharCursor.java new file mode 100755 index 00000000..20a0ec58 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/CharCursor.java @@ -0,0 +1,19 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over a collection of chars. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCursor.java") +public final class CharCursor { + /** + * The current value's index in the container this cursor belongs to. The meaning of this index is + * defined by the container (usually it will be an index in the underlying storage buffer). + */ + public int index; + + /** The current value. */ + public char value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/CharDoubleCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/CharDoubleCursor.java new file mode 100755 index 00000000..5cdcd581 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/CharDoubleCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (char keys and double values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class CharDoubleCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public char key; + + /** The current value. */ + public double value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/CharFloatCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/CharFloatCursor.java new file mode 100755 index 00000000..109f0ae3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/CharFloatCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (char keys and float values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class CharFloatCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public char key; + + /** The current value. */ + public float value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/CharIntCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/CharIntCursor.java new file mode 100755 index 00000000..b706f1f4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/CharIntCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (char keys and int values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class CharIntCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public char key; + + /** The current value. */ + public int value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/CharLongCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/CharLongCursor.java new file mode 100755 index 00000000..1d5259ff --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/CharLongCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (char keys and long values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class CharLongCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public char key; + + /** The current value. */ + public long value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/CharObjectCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/CharObjectCursor.java new file mode 100755 index 00000000..fa98d620 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/CharObjectCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (char keys and Object values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class CharObjectCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public char key; + + /** The current value. */ + public VType value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/CharShortCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/CharShortCursor.java new file mode 100755 index 00000000..d6407c80 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/CharShortCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (char keys and short values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class CharShortCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public char key; + + /** The current value. */ + public short value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/DoubleCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/DoubleCursor.java new file mode 100755 index 00000000..cc4f42c9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/DoubleCursor.java @@ -0,0 +1,19 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over a collection of doubles. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCursor.java") +public final class DoubleCursor { + /** + * The current value's index in the container this cursor belongs to. The meaning of this index is + * defined by the container (usually it will be an index in the underlying storage buffer). + */ + public int index; + + /** The current value. */ + public double value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/FloatCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/FloatCursor.java new file mode 100755 index 00000000..417f27eb --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/FloatCursor.java @@ -0,0 +1,19 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over a collection of floats. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCursor.java") +public final class FloatCursor { + /** + * The current value's index in the container this cursor belongs to. The meaning of this index is + * defined by the container (usually it will be an index in the underlying storage buffer). + */ + public int index; + + /** The current value. */ + public float value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/IntByteCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/IntByteCursor.java new file mode 100755 index 00000000..b0dede73 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/IntByteCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (int keys and byte values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class IntByteCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public int key; + + /** The current value. */ + public byte value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/IntCharCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/IntCharCursor.java new file mode 100755 index 00000000..d49fd001 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/IntCharCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (int keys and char values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class IntCharCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public int key; + + /** The current value. */ + public char value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/IntCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/IntCursor.java new file mode 100755 index 00000000..8fd34781 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/IntCursor.java @@ -0,0 +1,19 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over a collection of ints. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCursor.java") +public final class IntCursor { + /** + * The current value's index in the container this cursor belongs to. The meaning of this index is + * defined by the container (usually it will be an index in the underlying storage buffer). + */ + public int index; + + /** The current value. */ + public int value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/IntDoubleCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/IntDoubleCursor.java new file mode 100755 index 00000000..03e56888 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/IntDoubleCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (int keys and double values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class IntDoubleCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public int key; + + /** The current value. */ + public double value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/IntFloatCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/IntFloatCursor.java new file mode 100755 index 00000000..0cbc76e1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/IntFloatCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (int keys and float values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class IntFloatCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public int key; + + /** The current value. */ + public float value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/IntIntCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/IntIntCursor.java new file mode 100755 index 00000000..c02ea79e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/IntIntCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (int keys and int values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class IntIntCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public int key; + + /** The current value. */ + public int value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/IntLongCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/IntLongCursor.java new file mode 100755 index 00000000..299ad712 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/IntLongCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (int keys and long values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class IntLongCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public int key; + + /** The current value. */ + public long value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/IntObjectCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/IntObjectCursor.java new file mode 100755 index 00000000..673a06d1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/IntObjectCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (int keys and Object values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class IntObjectCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public int key; + + /** The current value. */ + public VType value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/IntShortCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/IntShortCursor.java new file mode 100755 index 00000000..7f72eba4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/IntShortCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (int keys and short values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class IntShortCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public int key; + + /** The current value. */ + public short value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/LongByteCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/LongByteCursor.java new file mode 100755 index 00000000..74cdbd90 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/LongByteCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (long keys and byte values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class LongByteCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public long key; + + /** The current value. */ + public byte value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/LongCharCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/LongCharCursor.java new file mode 100755 index 00000000..800389a1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/LongCharCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (long keys and char values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class LongCharCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public long key; + + /** The current value. */ + public char value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/LongCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/LongCursor.java new file mode 100755 index 00000000..53da311c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/LongCursor.java @@ -0,0 +1,19 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over a collection of longs. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCursor.java") +public final class LongCursor { + /** + * The current value's index in the container this cursor belongs to. The meaning of this index is + * defined by the container (usually it will be an index in the underlying storage buffer). + */ + public int index; + + /** The current value. */ + public long value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/LongDoubleCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/LongDoubleCursor.java new file mode 100755 index 00000000..ed4ceef2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/LongDoubleCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (long keys and double values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class LongDoubleCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public long key; + + /** The current value. */ + public double value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/LongFloatCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/LongFloatCursor.java new file mode 100755 index 00000000..0ff3ebb7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/LongFloatCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (long keys and float values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class LongFloatCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public long key; + + /** The current value. */ + public float value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/LongIntCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/LongIntCursor.java new file mode 100755 index 00000000..202d409a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/LongIntCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (long keys and int values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class LongIntCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public long key; + + /** The current value. */ + public int value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/LongLongCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/LongLongCursor.java new file mode 100755 index 00000000..824852f8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/LongLongCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (long keys and long values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class LongLongCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public long key; + + /** The current value. */ + public long value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/LongObjectCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/LongObjectCursor.java new file mode 100755 index 00000000..26f413c0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/LongObjectCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (long keys and Object values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class LongObjectCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public long key; + + /** The current value. */ + public VType value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/LongShortCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/LongShortCursor.java new file mode 100755 index 00000000..5d82d4e5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/LongShortCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (long keys and short values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class LongShortCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public long key; + + /** The current value. */ + public short value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ObjectByteCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ObjectByteCursor.java new file mode 100755 index 00000000..380b48af --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ObjectByteCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (Object keys and byte values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class ObjectByteCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public KType key; + + /** The current value. */ + public byte value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ObjectCharCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ObjectCharCursor.java new file mode 100755 index 00000000..1e4df4fc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ObjectCharCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (Object keys and char values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class ObjectCharCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public KType key; + + /** The current value. */ + public char value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ObjectCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ObjectCursor.java new file mode 100755 index 00000000..9f3ef5c0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ObjectCursor.java @@ -0,0 +1,19 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over a collection of Objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCursor.java") +public final class ObjectCursor { + /** + * The current value's index in the container this cursor belongs to. The meaning of this index is + * defined by the container (usually it will be an index in the underlying storage buffer). + */ + public int index; + + /** The current value. */ + public KType value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ObjectDoubleCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ObjectDoubleCursor.java new file mode 100755 index 00000000..edc16aea --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ObjectDoubleCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (Object keys and double values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class ObjectDoubleCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public KType key; + + /** The current value. */ + public double value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ObjectFloatCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ObjectFloatCursor.java new file mode 100755 index 00000000..767777e4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ObjectFloatCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (Object keys and float values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class ObjectFloatCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public KType key; + + /** The current value. */ + public float value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ObjectIntCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ObjectIntCursor.java new file mode 100755 index 00000000..b83b3672 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ObjectIntCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (Object keys and int values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class ObjectIntCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public KType key; + + /** The current value. */ + public int value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ObjectLongCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ObjectLongCursor.java new file mode 100755 index 00000000..4eba0b0b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ObjectLongCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (Object keys and long values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class ObjectLongCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public KType key; + + /** The current value. */ + public long value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ObjectObjectCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ObjectObjectCursor.java new file mode 100755 index 00000000..85514da4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ObjectObjectCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (Object keys and Object values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class ObjectObjectCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public KType key; + + /** The current value. */ + public VType value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ObjectShortCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ObjectShortCursor.java new file mode 100755 index 00000000..30f6fa60 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ObjectShortCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (Object keys and short values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class ObjectShortCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public KType key; + + /** The current value. */ + public short value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ShortByteCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ShortByteCursor.java new file mode 100755 index 00000000..1a2bd555 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ShortByteCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (short keys and byte values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class ShortByteCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public short key; + + /** The current value. */ + public byte value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ShortCharCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ShortCharCursor.java new file mode 100755 index 00000000..120fd566 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ShortCharCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (short keys and char values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class ShortCharCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public short key; + + /** The current value. */ + public char value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ShortCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ShortCursor.java new file mode 100755 index 00000000..37117970 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ShortCursor.java @@ -0,0 +1,19 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over a collection of shorts. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCursor.java") +public final class ShortCursor { + /** + * The current value's index in the container this cursor belongs to. The meaning of this index is + * defined by the container (usually it will be an index in the underlying storage buffer). + */ + public int index; + + /** The current value. */ + public short value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ShortDoubleCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ShortDoubleCursor.java new file mode 100755 index 00000000..f4b2d389 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ShortDoubleCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (short keys and double values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class ShortDoubleCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public short key; + + /** The current value. */ + public double value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ShortFloatCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ShortFloatCursor.java new file mode 100755 index 00000000..8a605078 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ShortFloatCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (short keys and float values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class ShortFloatCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public short key; + + /** The current value. */ + public float value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ShortIntCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ShortIntCursor.java new file mode 100755 index 00000000..997a6792 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ShortIntCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (short keys and int values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class ShortIntCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public short key; + + /** The current value. */ + public int value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ShortLongCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ShortLongCursor.java new file mode 100755 index 00000000..576e7f0e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ShortLongCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (short keys and long values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class ShortLongCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public short key; + + /** The current value. */ + public long value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ShortObjectCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ShortObjectCursor.java new file mode 100755 index 00000000..485514f6 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ShortObjectCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (short keys and Object values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class ShortObjectCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public short key; + + /** The current value. */ + public VType value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/cursors/ShortShortCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ShortShortCursor.java new file mode 100755 index 00000000..5fa724eb --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ShortShortCursor.java @@ -0,0 +1,23 @@ +package com.carrotsearch.hppc.cursors; + +/** A cursor over entries of an associative container (short keys and short values). */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeCursor.java") +public final class ShortShortCursor { + /** + * The current key and value's index in the container this cursor belongs to. The meaning of this + * index is defined by the container (usually it will be an index in the underlying storage + * buffer). + */ + public int index; + + /** The current key. */ + public short key; + + /** The current value. */ + public short value; + + @Override + public String toString() { + return "[cursor, index: " + index + ", key: " + key + ", value: " + value + "]"; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/internals/SuppressForbidden.java b/src/main/java/com/carrotsearch/hppc/internals/SuppressForbidden.java new file mode 100755 index 00000000..c746e0f7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/internals/SuppressForbidden.java @@ -0,0 +1,20 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc.internals; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** Suppresses forbidden-API checks. */ +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE}) +public @interface SuppressForbidden {} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ByteBytePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ByteBytePredicate.java new file mode 100755 index 00000000..d3819903 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ByteBytePredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to byte, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ByteBytePredicate { + public boolean apply(byte key, byte value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ByteCharPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ByteCharPredicate.java new file mode 100755 index 00000000..7e1877cc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ByteCharPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to byte, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ByteCharPredicate { + public boolean apply(byte key, char value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ByteDoublePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ByteDoublePredicate.java new file mode 100755 index 00000000..598b185b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ByteDoublePredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to byte, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ByteDoublePredicate { + public boolean apply(byte key, double value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ByteFloatPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ByteFloatPredicate.java new file mode 100755 index 00000000..0a7dde15 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ByteFloatPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to byte, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ByteFloatPredicate { + public boolean apply(byte key, float value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ByteIntPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ByteIntPredicate.java new file mode 100755 index 00000000..8b523f51 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ByteIntPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to byte, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ByteIntPredicate { + public boolean apply(byte key, int value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ByteLongPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ByteLongPredicate.java new file mode 100755 index 00000000..bff16b84 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ByteLongPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to byte, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ByteLongPredicate { + public boolean apply(byte key, long value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ByteObjectPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ByteObjectPredicate.java new file mode 100755 index 00000000..322f132b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ByteObjectPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to byte, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ByteObjectPredicate { + public boolean apply(byte key, VType value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/BytePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/BytePredicate.java new file mode 100755 index 00000000..16c023b1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/BytePredicate.java @@ -0,0 +1,7 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to byte objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypePredicate.java") +public interface BytePredicate { + public boolean apply(byte value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ByteShortPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ByteShortPredicate.java new file mode 100755 index 00000000..975073f7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ByteShortPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to byte, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ByteShortPredicate { + public boolean apply(byte key, short value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/CharBytePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/CharBytePredicate.java new file mode 100755 index 00000000..1bd258e4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/CharBytePredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to char, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface CharBytePredicate { + public boolean apply(char key, byte value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/CharCharPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/CharCharPredicate.java new file mode 100755 index 00000000..b2142e99 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/CharCharPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to char, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface CharCharPredicate { + public boolean apply(char key, char value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/CharDoublePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/CharDoublePredicate.java new file mode 100755 index 00000000..d7409d75 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/CharDoublePredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to char, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface CharDoublePredicate { + public boolean apply(char key, double value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/CharFloatPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/CharFloatPredicate.java new file mode 100755 index 00000000..d2e3c890 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/CharFloatPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to char, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface CharFloatPredicate { + public boolean apply(char key, float value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/CharIntPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/CharIntPredicate.java new file mode 100755 index 00000000..e68d9dac --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/CharIntPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to char, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface CharIntPredicate { + public boolean apply(char key, int value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/CharLongPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/CharLongPredicate.java new file mode 100755 index 00000000..de3ed2dc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/CharLongPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to char, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface CharLongPredicate { + public boolean apply(char key, long value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/CharObjectPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/CharObjectPredicate.java new file mode 100755 index 00000000..c85875e6 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/CharObjectPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to char, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface CharObjectPredicate { + public boolean apply(char key, VType value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/CharPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/CharPredicate.java new file mode 100755 index 00000000..efe6e9dc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/CharPredicate.java @@ -0,0 +1,7 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to char objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypePredicate.java") +public interface CharPredicate { + public boolean apply(char value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/CharShortPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/CharShortPredicate.java new file mode 100755 index 00000000..54d462c2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/CharShortPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to char, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface CharShortPredicate { + public boolean apply(char key, short value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/DoubleBytePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/DoubleBytePredicate.java new file mode 100755 index 00000000..1ab1d41c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/DoubleBytePredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to double, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface DoubleBytePredicate { + public boolean apply(double key, byte value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/DoubleCharPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/DoubleCharPredicate.java new file mode 100755 index 00000000..ac7f394e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/DoubleCharPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to double, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface DoubleCharPredicate { + public boolean apply(double key, char value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/DoubleDoublePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/DoubleDoublePredicate.java new file mode 100755 index 00000000..d3e39487 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/DoubleDoublePredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to double, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface DoubleDoublePredicate { + public boolean apply(double key, double value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/DoubleFloatPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/DoubleFloatPredicate.java new file mode 100755 index 00000000..1a0343d8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/DoubleFloatPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to double, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface DoubleFloatPredicate { + public boolean apply(double key, float value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/DoubleIntPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/DoubleIntPredicate.java new file mode 100755 index 00000000..a1a135be --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/DoubleIntPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to double, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface DoubleIntPredicate { + public boolean apply(double key, int value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/DoubleLongPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/DoubleLongPredicate.java new file mode 100755 index 00000000..2014b2a1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/DoubleLongPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to double, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface DoubleLongPredicate { + public boolean apply(double key, long value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/DoubleObjectPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/DoubleObjectPredicate.java new file mode 100755 index 00000000..290912f9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/DoubleObjectPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to double, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface DoubleObjectPredicate { + public boolean apply(double key, VType value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/DoublePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/DoublePredicate.java new file mode 100755 index 00000000..57227e9f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/DoublePredicate.java @@ -0,0 +1,7 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to double objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypePredicate.java") +public interface DoublePredicate { + public boolean apply(double value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/DoubleShortPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/DoubleShortPredicate.java new file mode 100755 index 00000000..6ee48dbf --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/DoubleShortPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to double, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface DoubleShortPredicate { + public boolean apply(double key, short value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/FloatBytePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/FloatBytePredicate.java new file mode 100755 index 00000000..07a763b5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/FloatBytePredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to float, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface FloatBytePredicate { + public boolean apply(float key, byte value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/FloatCharPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/FloatCharPredicate.java new file mode 100755 index 00000000..a14461d7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/FloatCharPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to float, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface FloatCharPredicate { + public boolean apply(float key, char value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/FloatDoublePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/FloatDoublePredicate.java new file mode 100755 index 00000000..8c8dda0d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/FloatDoublePredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to float, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface FloatDoublePredicate { + public boolean apply(float key, double value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/FloatFloatPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/FloatFloatPredicate.java new file mode 100755 index 00000000..fae9df7a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/FloatFloatPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to float, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface FloatFloatPredicate { + public boolean apply(float key, float value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/FloatIntPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/FloatIntPredicate.java new file mode 100755 index 00000000..dd37320b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/FloatIntPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to float, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface FloatIntPredicate { + public boolean apply(float key, int value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/FloatLongPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/FloatLongPredicate.java new file mode 100755 index 00000000..ed1232a7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/FloatLongPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to float, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface FloatLongPredicate { + public boolean apply(float key, long value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/FloatObjectPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/FloatObjectPredicate.java new file mode 100755 index 00000000..a74dca85 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/FloatObjectPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to float, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface FloatObjectPredicate { + public boolean apply(float key, VType value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/FloatPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/FloatPredicate.java new file mode 100755 index 00000000..eb728862 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/FloatPredicate.java @@ -0,0 +1,7 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to float objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypePredicate.java") +public interface FloatPredicate { + public boolean apply(float value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/FloatShortPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/FloatShortPredicate.java new file mode 100755 index 00000000..1a61beb0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/FloatShortPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to float, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface FloatShortPredicate { + public boolean apply(float key, short value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/IntBytePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/IntBytePredicate.java new file mode 100755 index 00000000..3bfa0aac --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/IntBytePredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to int, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface IntBytePredicate { + public boolean apply(int key, byte value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/IntCharPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/IntCharPredicate.java new file mode 100755 index 00000000..c262f415 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/IntCharPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to int, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface IntCharPredicate { + public boolean apply(int key, char value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/IntDoublePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/IntDoublePredicate.java new file mode 100755 index 00000000..3ec64db1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/IntDoublePredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to int, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface IntDoublePredicate { + public boolean apply(int key, double value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/IntFloatPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/IntFloatPredicate.java new file mode 100755 index 00000000..449b5f0d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/IntFloatPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to int, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface IntFloatPredicate { + public boolean apply(int key, float value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/IntIntPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/IntIntPredicate.java new file mode 100755 index 00000000..384d33cd --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/IntIntPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to int, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface IntIntPredicate { + public boolean apply(int key, int value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/IntLongPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/IntLongPredicate.java new file mode 100755 index 00000000..f3d4811b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/IntLongPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to int, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface IntLongPredicate { + public boolean apply(int key, long value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/IntObjectPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/IntObjectPredicate.java new file mode 100755 index 00000000..5a8063a8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/IntObjectPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to int, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface IntObjectPredicate { + public boolean apply(int key, VType value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/IntPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/IntPredicate.java new file mode 100755 index 00000000..77d1c38f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/IntPredicate.java @@ -0,0 +1,7 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to int objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypePredicate.java") +public interface IntPredicate { + public boolean apply(int value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/IntShortPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/IntShortPredicate.java new file mode 100755 index 00000000..443642d7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/IntShortPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to int, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface IntShortPredicate { + public boolean apply(int key, short value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/LongBytePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/LongBytePredicate.java new file mode 100755 index 00000000..dce65d8e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/LongBytePredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to long, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface LongBytePredicate { + public boolean apply(long key, byte value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/LongCharPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/LongCharPredicate.java new file mode 100755 index 00000000..f2974d72 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/LongCharPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to long, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface LongCharPredicate { + public boolean apply(long key, char value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/LongDoublePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/LongDoublePredicate.java new file mode 100755 index 00000000..34947e08 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/LongDoublePredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to long, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface LongDoublePredicate { + public boolean apply(long key, double value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/LongFloatPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/LongFloatPredicate.java new file mode 100755 index 00000000..c0bf1e54 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/LongFloatPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to long, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface LongFloatPredicate { + public boolean apply(long key, float value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/LongIntPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/LongIntPredicate.java new file mode 100755 index 00000000..a31d293a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/LongIntPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to long, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface LongIntPredicate { + public boolean apply(long key, int value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/LongLongPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/LongLongPredicate.java new file mode 100755 index 00000000..45315193 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/LongLongPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to long, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface LongLongPredicate { + public boolean apply(long key, long value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/LongObjectPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/LongObjectPredicate.java new file mode 100755 index 00000000..fef9bbc3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/LongObjectPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to long, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface LongObjectPredicate { + public boolean apply(long key, VType value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/LongPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/LongPredicate.java new file mode 100755 index 00000000..52f0b87a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/LongPredicate.java @@ -0,0 +1,7 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to long objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypePredicate.java") +public interface LongPredicate { + public boolean apply(long value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/LongShortPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/LongShortPredicate.java new file mode 100755 index 00000000..5621fd73 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/LongShortPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to long, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface LongShortPredicate { + public boolean apply(long key, short value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ObjectBytePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ObjectBytePredicate.java new file mode 100755 index 00000000..57657903 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ObjectBytePredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to Object, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ObjectBytePredicate { + public boolean apply(KType key, byte value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ObjectCharPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ObjectCharPredicate.java new file mode 100755 index 00000000..2c108dbb --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ObjectCharPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to Object, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ObjectCharPredicate { + public boolean apply(KType key, char value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ObjectDoublePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ObjectDoublePredicate.java new file mode 100755 index 00000000..e8d4ff50 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ObjectDoublePredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to Object, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ObjectDoublePredicate { + public boolean apply(KType key, double value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ObjectFloatPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ObjectFloatPredicate.java new file mode 100755 index 00000000..166d0c56 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ObjectFloatPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to Object, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ObjectFloatPredicate { + public boolean apply(KType key, float value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ObjectIntPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ObjectIntPredicate.java new file mode 100755 index 00000000..d683332c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ObjectIntPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to Object, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ObjectIntPredicate { + public boolean apply(KType key, int value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ObjectLongPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ObjectLongPredicate.java new file mode 100755 index 00000000..bd97d954 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ObjectLongPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to Object, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ObjectLongPredicate { + public boolean apply(KType key, long value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ObjectObjectPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ObjectObjectPredicate.java new file mode 100755 index 00000000..6970aa65 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ObjectObjectPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to Object, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ObjectObjectPredicate { + public boolean apply(KType key, VType value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ObjectPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ObjectPredicate.java new file mode 100755 index 00000000..c9426651 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ObjectPredicate.java @@ -0,0 +1,7 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to Object objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypePredicate.java") +public interface ObjectPredicate { + public boolean apply(KType value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ObjectShortPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ObjectShortPredicate.java new file mode 100755 index 00000000..2049fabf --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ObjectShortPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to Object, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ObjectShortPredicate { + public boolean apply(KType key, short value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ShortBytePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ShortBytePredicate.java new file mode 100755 index 00000000..86305fa4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ShortBytePredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to short, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ShortBytePredicate { + public boolean apply(short key, byte value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ShortCharPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ShortCharPredicate.java new file mode 100755 index 00000000..14a726ef --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ShortCharPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to short, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ShortCharPredicate { + public boolean apply(short key, char value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ShortDoublePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ShortDoublePredicate.java new file mode 100755 index 00000000..1fdd8733 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ShortDoublePredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to short, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ShortDoublePredicate { + public boolean apply(short key, double value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ShortFloatPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ShortFloatPredicate.java new file mode 100755 index 00000000..4a55b962 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ShortFloatPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to short, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ShortFloatPredicate { + public boolean apply(short key, float value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ShortIntPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ShortIntPredicate.java new file mode 100755 index 00000000..039c59ab --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ShortIntPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to short, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ShortIntPredicate { + public boolean apply(short key, int value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ShortLongPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ShortLongPredicate.java new file mode 100755 index 00000000..7036942c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ShortLongPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to short, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ShortLongPredicate { + public boolean apply(short key, long value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ShortObjectPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ShortObjectPredicate.java new file mode 100755 index 00000000..1b4bf8b7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ShortObjectPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to short, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ShortObjectPredicate { + public boolean apply(short key, VType value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ShortPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ShortPredicate.java new file mode 100755 index 00000000..40fa91c8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ShortPredicate.java @@ -0,0 +1,7 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to short objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypePredicate.java") +public interface ShortPredicate { + public boolean apply(short value); +} diff --git a/src/main/java/com/carrotsearch/hppc/predicates/ShortShortPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ShortShortPredicate.java new file mode 100755 index 00000000..51d7b0a7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ShortShortPredicate.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.predicates; + +/** A predicate that applies to short, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypePredicate.java") +public interface ShortShortPredicate { + public boolean apply(short key, short value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ByteByteProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ByteByteProcedure.java new file mode 100755 index 00000000..bd4a18ef --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ByteByteProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to byte, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ByteByteProcedure { + public void apply(byte key, byte value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ByteCharProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ByteCharProcedure.java new file mode 100755 index 00000000..6b4c5dea --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ByteCharProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to byte, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ByteCharProcedure { + public void apply(byte key, char value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ByteDoubleProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ByteDoubleProcedure.java new file mode 100755 index 00000000..3269170a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ByteDoubleProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to byte, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ByteDoubleProcedure { + public void apply(byte key, double value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ByteFloatProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ByteFloatProcedure.java new file mode 100755 index 00000000..011427e7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ByteFloatProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to byte, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ByteFloatProcedure { + public void apply(byte key, float value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ByteIntProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ByteIntProcedure.java new file mode 100755 index 00000000..aca3dc2f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ByteIntProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to byte, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ByteIntProcedure { + public void apply(byte key, int value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ByteLongProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ByteLongProcedure.java new file mode 100755 index 00000000..01e9239e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ByteLongProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to byte, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ByteLongProcedure { + public void apply(byte key, long value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ByteObjectProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ByteObjectProcedure.java new file mode 100755 index 00000000..8d954b0d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ByteObjectProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to byte, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ByteObjectProcedure { + public void apply(byte key, VType value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ByteProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ByteProcedure.java new file mode 100755 index 00000000..9959f0d1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ByteProcedure.java @@ -0,0 +1,7 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to byte objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeProcedure.java") +public interface ByteProcedure { + public void apply(byte value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ByteShortProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ByteShortProcedure.java new file mode 100755 index 00000000..83e34cc9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ByteShortProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to byte, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ByteShortProcedure { + public void apply(byte key, short value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/CharByteProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/CharByteProcedure.java new file mode 100755 index 00000000..58fa2d40 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/CharByteProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to char, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface CharByteProcedure { + public void apply(char key, byte value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/CharCharProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/CharCharProcedure.java new file mode 100755 index 00000000..2cd5d298 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/CharCharProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to char, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface CharCharProcedure { + public void apply(char key, char value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/CharDoubleProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/CharDoubleProcedure.java new file mode 100755 index 00000000..091e5c9d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/CharDoubleProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to char, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface CharDoubleProcedure { + public void apply(char key, double value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/CharFloatProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/CharFloatProcedure.java new file mode 100755 index 00000000..73b54532 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/CharFloatProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to char, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface CharFloatProcedure { + public void apply(char key, float value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/CharIntProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/CharIntProcedure.java new file mode 100755 index 00000000..8118508d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/CharIntProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to char, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface CharIntProcedure { + public void apply(char key, int value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/CharLongProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/CharLongProcedure.java new file mode 100755 index 00000000..9657edd1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/CharLongProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to char, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface CharLongProcedure { + public void apply(char key, long value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/CharObjectProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/CharObjectProcedure.java new file mode 100755 index 00000000..145e6f7d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/CharObjectProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to char, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface CharObjectProcedure { + public void apply(char key, VType value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/CharProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/CharProcedure.java new file mode 100755 index 00000000..2bd7e5d3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/CharProcedure.java @@ -0,0 +1,7 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to char objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeProcedure.java") +public interface CharProcedure { + public void apply(char value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/CharShortProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/CharShortProcedure.java new file mode 100755 index 00000000..50b2584f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/CharShortProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to char, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface CharShortProcedure { + public void apply(char key, short value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/DoubleByteProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/DoubleByteProcedure.java new file mode 100755 index 00000000..70adadf6 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/DoubleByteProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to double, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface DoubleByteProcedure { + public void apply(double key, byte value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/DoubleCharProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/DoubleCharProcedure.java new file mode 100755 index 00000000..101e0d99 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/DoubleCharProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to double, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface DoubleCharProcedure { + public void apply(double key, char value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/DoubleDoubleProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/DoubleDoubleProcedure.java new file mode 100755 index 00000000..9ba2012c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/DoubleDoubleProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to double, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface DoubleDoubleProcedure { + public void apply(double key, double value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/DoubleFloatProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/DoubleFloatProcedure.java new file mode 100755 index 00000000..3dabb0c9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/DoubleFloatProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to double, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface DoubleFloatProcedure { + public void apply(double key, float value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/DoubleIntProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/DoubleIntProcedure.java new file mode 100755 index 00000000..be62b25a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/DoubleIntProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to double, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface DoubleIntProcedure { + public void apply(double key, int value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/DoubleLongProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/DoubleLongProcedure.java new file mode 100755 index 00000000..a648e97a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/DoubleLongProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to double, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface DoubleLongProcedure { + public void apply(double key, long value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/DoubleObjectProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/DoubleObjectProcedure.java new file mode 100755 index 00000000..5973dd22 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/DoubleObjectProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to double, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface DoubleObjectProcedure { + public void apply(double key, VType value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/DoubleProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/DoubleProcedure.java new file mode 100755 index 00000000..c23a5617 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/DoubleProcedure.java @@ -0,0 +1,7 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to double objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeProcedure.java") +public interface DoubleProcedure { + public void apply(double value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/DoubleShortProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/DoubleShortProcedure.java new file mode 100755 index 00000000..aea0b9ec --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/DoubleShortProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to double, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface DoubleShortProcedure { + public void apply(double key, short value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/FloatByteProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/FloatByteProcedure.java new file mode 100755 index 00000000..df914d43 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/FloatByteProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to float, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface FloatByteProcedure { + public void apply(float key, byte value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/FloatCharProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/FloatCharProcedure.java new file mode 100755 index 00000000..8d54dba1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/FloatCharProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to float, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface FloatCharProcedure { + public void apply(float key, char value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/FloatDoubleProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/FloatDoubleProcedure.java new file mode 100755 index 00000000..e398c47f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/FloatDoubleProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to float, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface FloatDoubleProcedure { + public void apply(float key, double value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/FloatFloatProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/FloatFloatProcedure.java new file mode 100755 index 00000000..00cfa5b4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/FloatFloatProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to float, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface FloatFloatProcedure { + public void apply(float key, float value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/FloatIntProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/FloatIntProcedure.java new file mode 100755 index 00000000..f09f375d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/FloatIntProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to float, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface FloatIntProcedure { + public void apply(float key, int value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/FloatLongProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/FloatLongProcedure.java new file mode 100755 index 00000000..ee7e3d89 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/FloatLongProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to float, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface FloatLongProcedure { + public void apply(float key, long value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/FloatObjectProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/FloatObjectProcedure.java new file mode 100755 index 00000000..3e23e199 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/FloatObjectProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to float, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface FloatObjectProcedure { + public void apply(float key, VType value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/FloatProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/FloatProcedure.java new file mode 100755 index 00000000..17543434 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/FloatProcedure.java @@ -0,0 +1,7 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to float objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeProcedure.java") +public interface FloatProcedure { + public void apply(float value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/FloatShortProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/FloatShortProcedure.java new file mode 100755 index 00000000..9ae0b7f8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/FloatShortProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to float, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface FloatShortProcedure { + public void apply(float key, short value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/IntByteProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/IntByteProcedure.java new file mode 100755 index 00000000..2232f85a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/IntByteProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to int, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface IntByteProcedure { + public void apply(int key, byte value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/IntCharProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/IntCharProcedure.java new file mode 100755 index 00000000..f5f1d509 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/IntCharProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to int, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface IntCharProcedure { + public void apply(int key, char value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/IntDoubleProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/IntDoubleProcedure.java new file mode 100755 index 00000000..1fca14bb --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/IntDoubleProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to int, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface IntDoubleProcedure { + public void apply(int key, double value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/IntFloatProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/IntFloatProcedure.java new file mode 100755 index 00000000..8c91a104 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/IntFloatProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to int, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface IntFloatProcedure { + public void apply(int key, float value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/IntIntProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/IntIntProcedure.java new file mode 100755 index 00000000..b870c6b8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/IntIntProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to int, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface IntIntProcedure { + public void apply(int key, int value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/IntLongProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/IntLongProcedure.java new file mode 100755 index 00000000..741858f0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/IntLongProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to int, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface IntLongProcedure { + public void apply(int key, long value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/IntObjectProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/IntObjectProcedure.java new file mode 100755 index 00000000..575a1f2a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/IntObjectProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to int, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface IntObjectProcedure { + public void apply(int key, VType value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/IntProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/IntProcedure.java new file mode 100755 index 00000000..4fab32fd --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/IntProcedure.java @@ -0,0 +1,7 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to int objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeProcedure.java") +public interface IntProcedure { + public void apply(int value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/IntShortProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/IntShortProcedure.java new file mode 100755 index 00000000..c3bac031 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/IntShortProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to int, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface IntShortProcedure { + public void apply(int key, short value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/LongByteProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/LongByteProcedure.java new file mode 100755 index 00000000..670af78b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/LongByteProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to long, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface LongByteProcedure { + public void apply(long key, byte value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/LongCharProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/LongCharProcedure.java new file mode 100755 index 00000000..5ca456d0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/LongCharProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to long, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface LongCharProcedure { + public void apply(long key, char value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/LongDoubleProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/LongDoubleProcedure.java new file mode 100755 index 00000000..2aaa2c3d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/LongDoubleProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to long, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface LongDoubleProcedure { + public void apply(long key, double value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/LongFloatProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/LongFloatProcedure.java new file mode 100755 index 00000000..6b88a579 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/LongFloatProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to long, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface LongFloatProcedure { + public void apply(long key, float value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/LongIntProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/LongIntProcedure.java new file mode 100755 index 00000000..297f3878 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/LongIntProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to long, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface LongIntProcedure { + public void apply(long key, int value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/LongLongProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/LongLongProcedure.java new file mode 100755 index 00000000..f9f1fba4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/LongLongProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to long, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface LongLongProcedure { + public void apply(long key, long value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/LongObjectProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/LongObjectProcedure.java new file mode 100755 index 00000000..2e0a8f86 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/LongObjectProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to long, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface LongObjectProcedure { + public void apply(long key, VType value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/LongProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/LongProcedure.java new file mode 100755 index 00000000..9397055f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/LongProcedure.java @@ -0,0 +1,7 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to long objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeProcedure.java") +public interface LongProcedure { + public void apply(long value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/LongShortProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/LongShortProcedure.java new file mode 100755 index 00000000..2ad0865a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/LongShortProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to long, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface LongShortProcedure { + public void apply(long key, short value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ObjectByteProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ObjectByteProcedure.java new file mode 100755 index 00000000..85d69130 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ObjectByteProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to Object, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ObjectByteProcedure { + public void apply(KType key, byte value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ObjectCharProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ObjectCharProcedure.java new file mode 100755 index 00000000..3393875f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ObjectCharProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to Object, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ObjectCharProcedure { + public void apply(KType key, char value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ObjectDoubleProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ObjectDoubleProcedure.java new file mode 100755 index 00000000..4d9345d2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ObjectDoubleProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to Object, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ObjectDoubleProcedure { + public void apply(KType key, double value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ObjectFloatProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ObjectFloatProcedure.java new file mode 100755 index 00000000..237c2863 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ObjectFloatProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to Object, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ObjectFloatProcedure { + public void apply(KType key, float value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ObjectIntProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ObjectIntProcedure.java new file mode 100755 index 00000000..11bb001c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ObjectIntProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to Object, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ObjectIntProcedure { + public void apply(KType key, int value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ObjectLongProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ObjectLongProcedure.java new file mode 100755 index 00000000..9aec4cdd --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ObjectLongProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to Object, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ObjectLongProcedure { + public void apply(KType key, long value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ObjectObjectProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ObjectObjectProcedure.java new file mode 100755 index 00000000..382d76f8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ObjectObjectProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to Object, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ObjectObjectProcedure { + public void apply(KType key, VType value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ObjectProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ObjectProcedure.java new file mode 100755 index 00000000..cb0f00fc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ObjectProcedure.java @@ -0,0 +1,7 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to Object objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeProcedure.java") +public interface ObjectProcedure { + public void apply(KType value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ObjectShortProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ObjectShortProcedure.java new file mode 100755 index 00000000..871cac43 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ObjectShortProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to Object, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ObjectShortProcedure { + public void apply(KType key, short value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ShortByteProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ShortByteProcedure.java new file mode 100755 index 00000000..a9b86f29 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ShortByteProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to short, byte pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ShortByteProcedure { + public void apply(short key, byte value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ShortCharProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ShortCharProcedure.java new file mode 100755 index 00000000..2ebbb819 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ShortCharProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to short, char pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ShortCharProcedure { + public void apply(short key, char value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ShortDoubleProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ShortDoubleProcedure.java new file mode 100755 index 00000000..ada12e27 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ShortDoubleProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to short, double pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ShortDoubleProcedure { + public void apply(short key, double value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ShortFloatProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ShortFloatProcedure.java new file mode 100755 index 00000000..a99af694 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ShortFloatProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to short, float pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ShortFloatProcedure { + public void apply(short key, float value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ShortIntProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ShortIntProcedure.java new file mode 100755 index 00000000..e633c55d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ShortIntProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to short, int pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ShortIntProcedure { + public void apply(short key, int value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ShortLongProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ShortLongProcedure.java new file mode 100755 index 00000000..99275f7e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ShortLongProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to short, long pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ShortLongProcedure { + public void apply(short key, long value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ShortObjectProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ShortObjectProcedure.java new file mode 100755 index 00000000..5ab91d02 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ShortObjectProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to short, Object pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ShortObjectProcedure { + public void apply(short key, VType value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ShortProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ShortProcedure.java new file mode 100755 index 00000000..d3482c7b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ShortProcedure.java @@ -0,0 +1,7 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to short objects. */ +@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeProcedure.java") +public interface ShortProcedure { + public void apply(short value); +} diff --git a/src/main/java/com/carrotsearch/hppc/procedures/ShortShortProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ShortShortProcedure.java new file mode 100755 index 00000000..05873e51 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ShortShortProcedure.java @@ -0,0 +1,9 @@ +package com.carrotsearch.hppc.procedures; + +/** A procedure that applies to short, short pairs. */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeProcedure.java") +public interface ShortShortProcedure { + public void apply(short key, short value); +} diff --git a/src/main/java/com/carrotsearch/hppc/sorting/IndirectSort.java b/src/main/java/com/carrotsearch/hppc/sorting/IndirectSort.java new file mode 100755 index 00000000..2d4722ed --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/sorting/IndirectSort.java @@ -0,0 +1,133 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc.sorting; + +import java.util.Comparator; +import java.util.function.IntBinaryOperator; + +/** + * Sorting routines that return an array of sorted indices implied by a given comparator rather than + * move elements of whatever the comparator is using for comparisons. + * + *

A practical use case for this class is when the index of an array is meaningful and one wants + * to acquire the order of values in that array. None of the methods in Java Collections would + * provide such functionality directly and creating a collection of boxed {@link Integer} objects + * for indices seems to be too costly. + */ +public final class IndirectSort { + /** Minimum window length to apply insertion sort in merge sort. */ + static int MIN_LENGTH_FOR_INSERTION_SORT = 30; + + /** No instantiation. */ + private IndirectSort() { + // No instantiation. + } + + /** + * Returns the order of elements between indices start and length, as + * indicated by the given comparator. + * + *

This routine uses merge sort. It is guaranteed to be stable. It creates a new indices array, + * and clones it while sorting. + */ + public static int[] mergesort(int start, int length, IntBinaryOperator comparator) { + final int[] src = createOrderArray(start, length); + return mergesort(src, comparator); + } + + /** + * Returns a sorted copy of the order array provided, using the given comparator. + * + *

This routine uses merge sort. It is guaranteed to be stable. The provided {@code + * indicesArray} is cloned while sorting and the clone is returned. + */ + public static int[] mergesort(int[] orderArray, IntBinaryOperator comparator) { + if (orderArray.length <= 1) { + return orderArray; + } + final int[] dst = orderArray.clone(); + topDownMergeSort(orderArray, dst, 0, orderArray.length, comparator); + return dst; + } + + /** + * Returns the order of elements between indices start and length, as + * indicated by the given comparator. + * + *

This routine uses merge sort. It is guaranteed to be stable. It creates a new indices array, + * and clones it while sorting. + */ + public static int[] mergesort( + T[] input, int start, int length, Comparator comparator) { + return mergesort(start, length, (a, b) -> comparator.compare(input[a], input[b])); + } + + /** + * Perform a recursive, descending merge sort. + * + * @param fromIndex inclusive + * @param toIndex exclusive + */ + private static void topDownMergeSort( + int[] src, int[] dst, int fromIndex, int toIndex, IntBinaryOperator comp) { + if (toIndex - fromIndex <= MIN_LENGTH_FOR_INSERTION_SORT) { + insertionSort(fromIndex, toIndex - fromIndex, dst, comp); + return; + } + + final int mid = (fromIndex + toIndex) >>> 1; + topDownMergeSort(dst, src, fromIndex, mid, comp); + topDownMergeSort(dst, src, mid, toIndex, comp); + + /* + * Both splits in of src are now sorted. + */ + if (comp.applyAsInt(src[mid - 1], src[mid]) <= 0) { + /* + * If the lowest element in upper slice is larger than the highest element in + * the lower slice, simply copy over, the data is fully sorted. + */ + System.arraycopy(src, fromIndex, dst, fromIndex, toIndex - fromIndex); + } else { + /* + * Run a manual merge. + */ + for (int i = fromIndex, j = mid, k = fromIndex; k < toIndex; k++) { + if (j == toIndex || (i < mid && comp.applyAsInt(src[i], src[j]) <= 0)) { + dst[k] = src[i++]; + } else { + dst[k] = src[j++]; + } + } + } + } + + /** Internal insertion sort for ints. */ + private static void insertionSort( + final int off, final int len, int[] order, IntBinaryOperator intComparator) { + for (int i = off + 1; i < off + len; i++) { + final int v = order[i]; + int j = i, t; + while (j > off && intComparator.applyAsInt(t = order[j - 1], v) > 0) { + order[j--] = t; + } + order[j] = v; + } + } + + /** Creates the initial order array. */ + private static int[] createOrderArray(final int start, final int length) { + final int[] order = new int[length]; + for (int i = 0; i < length; i++) { + order[i] = start + i; + } + return order; + } +} diff --git a/src/main/java/com/carrotsearch/hppc/sorting/QuickSort.java b/src/main/java/com/carrotsearch/hppc/sorting/QuickSort.java new file mode 100755 index 00000000..b547dc68 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/sorting/QuickSort.java @@ -0,0 +1,181 @@ +/* + * HPPC + * + * Copyright (C) 2010-2024 Carrot Search s.c. and contributors + * All rights reserved. + * + * Refer to the full license file "LICENSE.txt": + * https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt + */ +package com.carrotsearch.hppc.sorting; + +import java.util.function.IntBinaryOperator; + +/** + * In-place Quick sort with 3-way partitioning and ending with Insertion sort. + * + *

The sorting is not stable. Performance is O(n.log(n)) and memory is O(1) (although recursion + * memory is O(log(n))). + */ +public final class QuickSort { + + /** Below this size threshold, the sub-range is sorted using Insertion sort. */ + static final int INSERTION_SORT_THRESHOLD = 16; + + /** /** Below this size threshold, the partition selection is simplified to a single median. */ + static final int SINGLE_MEDIAN_THRESHOLD = 40; + + /** No instantiation. */ + private QuickSort() { + // No instantiation. + } + + /** + * @see #sort(int, int, IntBinaryOperator, IntBinaryOperator) + */ + public static void sort(int[] array, IntBinaryOperator comparator) { + sort(array, 0, array.length, comparator); + } + + /** + * @see #sort(int, int, IntBinaryOperator, IntBinaryOperator) + */ + public static void sort(int[] array, int fromIndex, int toIndex, IntBinaryOperator comparator) { + sort( + fromIndex, + toIndex, + comparator, + (i, j) -> { + int swap = array[i]; + array[i] = array[j]; + array[j] = swap; + return 0; + }); + } + + /** + * Performs a recursive in-place Quick sort. The sorting is not stable. + * + * @param fromIndex Index where to start sorting in the array, inclusive. + * @param toIndex Index where to stop sorting in the array, exclusive. + * @param comparator Compares elements based on their indices. Given indices i and j in the + * provided array, this comparator returns respectively -1/0/1 if the element at index i is + * respectively less/equal/greater than the element at index j. + * @param swapper Swaps the elements in the array at the given indices. For example, a custom + * swapper may allow sorting two arrays simultaneously. + */ + public static void sort( + int fromIndex, int toIndex, IntBinaryOperator comparator, IntBinaryOperator swapper) { + int size; + while ((size = toIndex - fromIndex) > INSERTION_SORT_THRESHOLD) { + + // Pivot selection. + int last = toIndex - 1; + int middle = (fromIndex + last) >>> 1; + int pivot; + if (size <= SINGLE_MEDIAN_THRESHOLD) { + // Select the pivot with a single median around the middle element. + // Do not take the median between [from, mid, last] because it hurts performance + // if the order is descending. + int range = size >> 2; + pivot = median(middle - range, middle, middle + range, comparator); + } else { + // Select the pivot with the median of medians. + int range = size >> 3; + int doubleRange = range << 1; + int medianStart = median(fromIndex, fromIndex + range, fromIndex + doubleRange, comparator); + int medianMiddle = median(middle - range, middle, middle + range, comparator); + int medianEnd = median(last - doubleRange, last - range, last, comparator); + pivot = median(medianStart, medianMiddle, medianEnd, comparator); + } + + // Bentley-McIlroy 3-way partitioning. + swap(fromIndex, pivot, swapper); + int i = fromIndex; + int j = toIndex; + int p = fromIndex + 1; + int q = last; + while (true) { + int leftCmp, rightCmp; + while ((leftCmp = compare(++i, fromIndex, comparator)) < 0) { + // repeat + } + while ((rightCmp = compare(--j, fromIndex, comparator)) > 0) { + // repeat + } + if (i >= j) { + if (i == j && rightCmp == 0) { + swap(i, p, swapper); + } + break; + } + swap(i, j, swapper); + if (rightCmp == 0) { + swap(i, p++, swapper); + } + if (leftCmp == 0) { + swap(j, q--, swapper); + } + } + i = j + 1; + for (int k = fromIndex; k < p; ) { + swap(k++, j--, swapper); + } + for (int k = last; k > q; ) { + swap(k--, i++, swapper); + } + + // Recursion on the smallest partition. + // Replace the tail recursion by a loop. + if (j - fromIndex < last - i) { + sort(fromIndex, j + 1, comparator, swapper); + fromIndex = i; + } else { + sort(i, toIndex, comparator, swapper); + toIndex = j + 1; + } + } + + insertionSort(fromIndex, toIndex, comparator, swapper); + } + + /** Sorts between from (inclusive) and to (exclusive) with insertion sort. */ + private static void insertionSort( + int fromIndex, int toIndex, IntBinaryOperator comparator, IntBinaryOperator swapper) { + for (int i = fromIndex + 1; i < toIndex; ) { + int current = i++; + int previous; + while (compare((previous = current - 1), current, comparator) > 0) { + swap(previous, current, swapper); + if (previous == fromIndex) { + break; + } + current = previous; + } + } + } + + /** Returns the index of the median element among three elements at provided indices. */ + private static int median(int i, int j, int k, IntBinaryOperator comparator) { + if (compare(i, j, comparator) < 0) { + if (compare(j, k, comparator) <= 0) { + return j; + } + return compare(i, k, comparator) < 0 ? k : i; + } + if (compare(j, k, comparator) >= 0) { + return j; + } + return compare(i, k, comparator) < 0 ? i : k; + } + + /** Compares two elements at provided indices. */ + private static int compare(int i, int j, IntBinaryOperator comparator) { + return comparator.applyAsInt(i, j); + } + + /** Swaps two elements at provided indices. */ + private static void swap(int i, int j, IntBinaryOperator swapper) { + swapper.applyAsInt(i, j); + } +} diff --git a/src/main/java/jdk_internal/bidi/Annotation.java b/src/main/java/jdk_internal/bidi/Annotation.java new file mode 100755 index 00000000..b0b6ed71 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/Annotation.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk_internal.bidi; + +/** + * An Annotation object is used as a wrapper for a text attribute value if the + * attribute has annotation characteristics. These characteristics are: + *

    + *
  • The text range that the attribute is applied to is critical to the + * semantics of the range. That means, the attribute cannot be applied to + * subranges of the text range that it applies to, and, if two adjacent text + * ranges have the same value for this attribute, the attribute still cannot be + * applied to the combined range as a whole with this value. + *
  • The attribute or its value usually do no longer apply if the underlying + * text is changed. + *
+ * + * An example is grammatical information attached to a sentence: For the + * previous sentence, you can say that "an example" is the subject, but you + * cannot say the same about "an", "example", or "exam". When the text is + * changed, the grammatical information typically becomes invalid. Another + * example is Japanese reading information (yomi). + * + *

+ * Wrapping the attribute value into an Annotation object guarantees that + * adjacent text runs don't get merged even if the attribute values are equal, + * and indicates to text containers that the attribute should be discarded if + * the underlying text is modified. + * + * @see AttributedCharacterIterator + * @since 1.2 + */ + +public class Annotation { + + /** + * Constructs an annotation record with the given value, which may be null. + * + * @param value the value of the attribute + */ + public Annotation(Object value) { + this.value = value; + } + + /** + * Returns the value of the attribute, which may be null. + * + * @return the value of the attribute + */ + public Object getValue() { + return value; + } + + /** + * Returns the String representation of this Annotation. + * + * @return the {@code String} representation of this {@code Annotation} + */ + public String toString() { + return getClass().getName() + "[value=" + value + "]"; + } + + private Object value; + +}; diff --git a/src/main/java/jdk_internal/bidi/AttributedCharacterIterator.java b/src/main/java/jdk_internal/bidi/AttributedCharacterIterator.java new file mode 100755 index 00000000..00223d36 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/AttributedCharacterIterator.java @@ -0,0 +1,299 @@ +/* + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk_internal.bidi; + +import java.io.InvalidObjectException; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * An {@code AttributedCharacterIterator} allows iteration through both text and + * related attribute information. + * + *

+ * An attribute is a key/value pair, identified by the key. No two attributes on + * a given character can have the same key. + * + *

+ * The values for an attribute are immutable, or must not be mutated by clients + * or storage. They are always passed by reference, and not cloned. + * + *

+ * A run with respect to an attribute is a maximum text range for + * which: + *

    + *
  • the attribute is undefined or {@code null} for the entire range, or + *
  • the attribute value is defined and has the same non-{@code null} value + * for the entire range. + *
+ * + *

+ * A run with respect to a set of attributes is a maximum text range + * for which this condition is met for each member attribute. + * + *

+ * When getting a run with no explicit attributes specified (i.e., calling + * {@link #getRunStart()} and {@link #getRunLimit()}), any contiguous text + * segments having the same attributes (the same set of attribute/value pairs) + * are treated as separate runs if the attributes have been given to those text + * segments separately. + * + *

+ * The returned indexes are limited to the range of the iterator. + * + *

+ * The returned attribute information is limited to runs that contain the + * current character. + * + *

+ * Attribute keys are instances of {@link AttributedCharacterIterator.Attribute} + * and its subclasses, such as {@link java.awt.font.TextAttribute}. + * + * @see AttributedCharacterIterator.Attribute + * @see java.awt.font.TextAttribute + * @see AttributedString + * @see Annotation + * @since 1.2 + */ + +public interface AttributedCharacterIterator extends CharacterIterator { + + /** + * Defines attribute keys that are used to identify text attributes. These keys + * are used in {@code AttributedCharacterIterator} and {@code AttributedString}. + * + * @see AttributedCharacterIterator + * @see AttributedString + * @since 1.2 + */ + + public static class Attribute implements Serializable { + + /** + * The name of this {@code Attribute}. The name is used primarily by + * {@code readResolve} to look up the corresponding predefined instance when + * deserializing an instance. + * + * @serial + */ + private String name; + + // table of all instances in this class, used by readResolve + private static final Map instanceMap = new HashMap<>(7); + + /** + * Constructs an {@code Attribute} with the given name. + * + * @param name the name of {@code Attribute} + */ + protected Attribute(String name) { + this.name = name; + if (this.getClass() == Attribute.class) { + instanceMap.put(name, this); + } + } + + /** + * Compares two objects for equality. This version only returns true for + * {@code x.equals(y)} if {@code x} and {@code y} refer to the same object, and + * guarantees this for all subclasses. + */ + public final boolean equals(Object obj) { + return super.equals(obj); + } + + /** + * Returns a hash code value for the object. This version is identical to the + * one in {@code Object}, but is also final. + */ + public final int hashCode() { + return super.hashCode(); + } + + /** + * Returns a string representation of the object. This version returns the + * concatenation of class name, {@code "("}, a name identifying the attribute + * and {@code ")"}. + */ + public String toString() { + return getClass().getName() + "(" + name + ")"; + } + + /** + * Returns the name of the attribute. + * + * @return the name of {@code Attribute} + */ + protected String getName() { + return name; + } + + /** + * Resolves instances being deserialized to the predefined constants. + * + * @return the resolved {@code Attribute} object + * @throws InvalidObjectException if the object to resolve is not an instance of + * {@code Attribute} + */ + protected Object readResolve() throws InvalidObjectException { + if (this.getClass() != Attribute.class) { + throw new InvalidObjectException("subclass didn't correctly implement readResolve"); + } + + Attribute instance = instanceMap.get(getName()); + if (instance != null) { + return instance; + } else { + throw new InvalidObjectException("unknown attribute name"); + } + } + + /** + * Attribute key for the language of some text. + *

+ * Values are instances of {@link java.util.Locale Locale}. + * + * @see java.util.Locale + */ + public static final Attribute LANGUAGE = new Attribute("language"); + + /** + * Attribute key for the reading of some text. In languages where the written + * form and the pronunciation of a word are only loosely related (such as + * Japanese), it is often necessary to store the reading (pronunciation) along + * with the written form. + *

+ * Values are instances of {@link Annotation} holding instances of + * {@link String}. + * + * @see Annotation + * @see java.lang.String + */ + public static final Attribute READING = new Attribute("reading"); + + /** + * Attribute key for input method segments. Input methods often break up text + * into segments, which usually correspond to words. + *

+ * Values are instances of {@link Annotation} holding a {@code null} reference. + * + * @see Annotation + */ + public static final Attribute INPUT_METHOD_SEGMENT = new Attribute("input_method_segment"); + + // make sure the serial version doesn't change between compiler versions + private static final long serialVersionUID = -9142742483513960612L; + + }; + + /** + * Returns the index of the first character of the run with respect to all + * attributes containing the current character. + * + *

+ * Any contiguous text segments having the same attributes (the same set of + * attribute/value pairs) are treated as separate runs if the attributes have + * been given to those text segments separately. + * + * @return the index of the first character of the run + */ + public int getRunStart(); + + /** + * Returns the index of the first character of the run with respect to the given + * {@code attribute} containing the current character. + * + * @param attribute the desired attribute. + * @return the index of the first character of the run + */ + public int getRunStart(Attribute attribute); + + /** + * Returns the index of the first character of the run with respect to the given + * {@code attributes} containing the current character. + * + * @param attributes a set of the desired attributes. + * @return the index of the first character of the run + */ + public int getRunStart(Set attributes); + + /** + * Returns the index of the first character following the run with respect to + * all attributes containing the current character. + * + *

+ * Any contiguous text segments having the same attributes (the same set of + * attribute/value pairs) are treated as separate runs if the attributes have + * been given to those text segments separately. + * + * @return the index of the first character following the run + */ + public int getRunLimit(); + + /** + * Returns the index of the first character following the run with respect to + * the given {@code attribute} containing the current character. + * + * @param attribute the desired attribute + * @return the index of the first character following the run + */ + public int getRunLimit(Attribute attribute); + + /** + * Returns the index of the first character following the run with respect to + * the given {@code attributes} containing the current character. + * + * @param attributes a set of the desired attributes + * @return the index of the first character following the run + */ + public int getRunLimit(Set attributes); + + /** + * Returns a map with the attributes defined on the current character. + * + * @return a map with the attributes defined on the current character + */ + public Map getAttributes(); + + /** + * Returns the value of the named {@code attribute} for the current character. + * Returns {@code null} if the {@code attribute} is not defined. + * + * @param attribute the desired attribute + * @return the value of the named {@code attribute} or {@code null} + */ + public Object getAttribute(Attribute attribute); + + /** + * Returns the keys of all attributes defined on the iterator's text range. The + * set is empty if no attributes are defined. + * + * @return the keys of all attributes + */ + public Set getAllAttributeKeys(); +}; diff --git a/src/main/java/jdk_internal/bidi/AttributedString.java b/src/main/java/jdk_internal/bidi/AttributedString.java new file mode 100755 index 00000000..cdabbc70 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/AttributedString.java @@ -0,0 +1,1109 @@ +/* + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk_internal.bidi; + +import java.util.*; + +import jdk_internal.bidi.AttributedCharacterIterator.Attribute; + +/** + * An AttributedString holds text and related attribute information. It may be + * used as the actual data storage in some cases where a text reader wants to + * access attributed text through the AttributedCharacterIterator interface. + * + *

+ * An attribute is a key/value pair, identified by the key. No two attributes on + * a given character can have the same key. + * + *

+ * The values for an attribute are immutable, or must not be mutated by clients + * or storage. They are always passed by reference, and not cloned. + * + * @see AttributedCharacterIterator + * @see Annotation + * @since 1.2 + */ + +public class AttributedString { + // field holding the text + String text; + + // Fields holding run attribute information. + // Run attributes are organized by run. + // Arrays are always of equal lengths (the current capacity). + // Since there are no vectors of int, we have to use arrays. + private static final int INITIAL_CAPACITY = 10; + int runCount; // actual number of runs, <= current capacity + int[] runStarts; // start index for each run + Vector[] runAttributes; // vector of attribute keys for each run + Vector[] runAttributeValues; // parallel vector of attribute values for each run + + /** + * Constructs an AttributedString instance with the given + * AttributedCharacterIterators. + * + * @param iterators AttributedCharacterIterators to construct AttributedString + * from. + * @throws NullPointerException if iterators is null + */ + AttributedString(AttributedCharacterIterator[] iterators) { + if (iterators == null) { + throw new NullPointerException("Iterators must not be null"); + } + if (iterators.length == 0) { + text = ""; + } else { + // Build the String contents + StringBuffer buffer = new StringBuffer(); + for (int counter = 0; counter < iterators.length; counter++) { + appendContents(buffer, iterators[counter]); + } + + text = buffer.toString(); + + if (!text.isEmpty()) { + // Determine the runs, creating a new run when the attributes + // differ. + int offset = 0; + Map last = null; + + for (int counter = 0; counter < iterators.length; counter++) { + AttributedCharacterIterator iterator = iterators[counter]; + int start = iterator.getBeginIndex(); + int end = iterator.getEndIndex(); + int index = start; + + while (index < end) { + iterator.setIndex(index); + + Map attrs = iterator.getAttributes(); + + if (mapsDiffer(last, attrs)) { + setAttributes(attrs, index - start + offset); + } + last = attrs; + index = iterator.getRunLimit(); + } + offset += (end - start); + } + } + } + } + + /** + * Constructs an AttributedString instance with the given text. + * + * @param text The text for this attributed string. + * @throws NullPointerException if {@code text} is null. + */ + public AttributedString(String text) { + if (text == null) { + throw new NullPointerException(); + } + this.text = text; + } + + /** + * Constructs an AttributedString instance with the given text and attributes. + * + * @param text The text for this attributed string. + * @param attributes The attributes that apply to the entire string. + * @throws NullPointerException if {@code text} or {@code attributes} is + * null. + * @throws IllegalArgumentException if the text has length 0 and the attributes + * parameter is not an empty Map (attributes + * cannot be applied to a 0-length range). + */ + public AttributedString(String text, Map attributes) { + if (text == null || attributes == null) { + throw new NullPointerException(); + } + this.text = text; + + if (text.isEmpty()) { + if (attributes.isEmpty()) + return; + throw new IllegalArgumentException("Can't add attribute to 0-length text"); + } + + int attributeCount = attributes.size(); + if (attributeCount > 0) { + createRunAttributeDataVectors(); + Vector newRunAttributes = new Vector<>(attributeCount); + Vector newRunAttributeValues = new Vector<>(attributeCount); + runAttributes[0] = newRunAttributes; + runAttributeValues[0] = newRunAttributeValues; + + Iterator> iterator = attributes.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + newRunAttributes.addElement(entry.getKey()); + newRunAttributeValues.addElement(entry.getValue()); + } + } + } + + /** + * Constructs an AttributedString instance with the given attributed text + * represented by AttributedCharacterIterator. + * + * @param text The text for this attributed string. + * @throws NullPointerException if {@code text} is null. + */ + public AttributedString(AttributedCharacterIterator text) { + // If performance is critical, this constructor should be + // implemented here rather than invoking the constructor for a + // subrange. We can avoid some range checking in the loops. + this(text, text.getBeginIndex(), text.getEndIndex(), null); + } + + /** + * Constructs an AttributedString instance with the subrange of the given + * attributed text represented by AttributedCharacterIterator. If the given + * range produces an empty text, all attributes will be discarded. Note that any + * attributes wrapped by an Annotation object are discarded for a subrange of + * the original attribute range. + * + * @param text The text for this attributed string. + * @param beginIndex Index of the first character of the range. + * @param endIndex Index of the character following the last character of the + * range. + * @throws NullPointerException if {@code text} is null. + * @throws IllegalArgumentException if the subrange given by beginIndex and + * endIndex is out of the text range. + * @see java.text.Annotation + */ + public AttributedString(AttributedCharacterIterator text, int beginIndex, int endIndex) { + this(text, beginIndex, endIndex, null); + } + + /** + * Constructs an AttributedString instance with the subrange of the given + * attributed text represented by AttributedCharacterIterator. Only attributes + * that match the given attributes will be incorporated into the instance. If + * the given range produces an empty text, all attributes will be discarded. + * Note that any attributes wrapped by an Annotation object are discarded for a + * subrange of the original attribute range. + * + * @param text The text for this attributed string. + * @param beginIndex Index of the first character of the range. + * @param endIndex Index of the character following the last character of the + * range. + * @param attributes Specifies attributes to be extracted from the text. If null + * is specified, all available attributes will be used. + * @throws NullPointerException if {@code text} is null. + * @throws IllegalArgumentException if the subrange given by beginIndex and + * endIndex is out of the text range. + * @see java.text.Annotation + */ + public AttributedString(AttributedCharacterIterator text, int beginIndex, int endIndex, Attribute[] attributes) { + if (text == null) { + throw new NullPointerException(); + } + + // Validate the given subrange + int textBeginIndex = text.getBeginIndex(); + int textEndIndex = text.getEndIndex(); + if (beginIndex < textBeginIndex || endIndex > textEndIndex || beginIndex > endIndex) + throw new IllegalArgumentException("Invalid substring range"); + + // Copy the given string + StringBuilder textBuilder = new StringBuilder(); + text.setIndex(beginIndex); + for (char c = text.current(); text.getIndex() < endIndex; c = text.next()) + textBuilder.append(c); + this.text = textBuilder.toString(); + + if (beginIndex == endIndex) + return; + + // Select attribute keys to be taken care of + HashSet keys = new HashSet<>(); + if (attributes == null) { + keys.addAll(text.getAllAttributeKeys()); + } else { + for (int i = 0; i < attributes.length; i++) + keys.add(attributes[i]); + keys.retainAll(text.getAllAttributeKeys()); + } + if (keys.isEmpty()) + return; + + // Get and set attribute runs for each attribute name. Need to + // scan from the top of the text so that we can discard any + // Annotation that is no longer applied to a subset text segment. + Iterator itr = keys.iterator(); + while (itr.hasNext()) { + Attribute attributeKey = itr.next(); + text.setIndex(textBeginIndex); + while (text.getIndex() < endIndex) { + int start = text.getRunStart(attributeKey); + int limit = text.getRunLimit(attributeKey); + Object value = text.getAttribute(attributeKey); + + if (value != null) { + if (value instanceof Annotation) { + if (start >= beginIndex && limit <= endIndex) { + addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex); + } else { + if (limit > endIndex) + break; + } + } else { + // if the run is beyond the given (subset) range, we + // don't need to process further. + if (start >= endIndex) + break; + if (limit > beginIndex) { + // attribute is applied to any subrange + if (start < beginIndex) + start = beginIndex; + if (limit > endIndex) + limit = endIndex; + if (start != limit) { + addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex); + } + } + } + } + text.setIndex(limit); + } + } + } + + /** + * Adds an attribute to the entire string. + * + * @param attribute the attribute key + * @param value the value of the attribute; may be null + * @throws NullPointerException if {@code attribute} is null. + * @throws IllegalArgumentException if the AttributedString has length 0 + * (attributes cannot be applied to a 0-length + * range). + */ + public void addAttribute(Attribute attribute, Object value) { + + if (attribute == null) { + throw new NullPointerException(); + } + + int len = length(); + if (len == 0) { + throw new IllegalArgumentException("Can't add attribute to 0-length text"); + } + + addAttributeImpl(attribute, value, 0, len); + } + + /** + * Adds an attribute to a subrange of the string. + * + * @param attribute the attribute key + * @param value The value of the attribute. May be null. + * @param beginIndex Index of the first character of the range. + * @param endIndex Index of the character following the last character of the + * range. + * @throws NullPointerException if {@code attribute} is null. + * @throws IllegalArgumentException if beginIndex is less than 0, endIndex is + * greater than the length of the string, or + * beginIndex and endIndex together don't + * define a non-empty subrange of the string. + */ + public void addAttribute(Attribute attribute, Object value, int beginIndex, int endIndex) { + + if (attribute == null) { + throw new NullPointerException(); + } + + if (beginIndex < 0 || endIndex > length() || beginIndex >= endIndex) { + throw new IllegalArgumentException("Invalid substring range"); + } + + addAttributeImpl(attribute, value, beginIndex, endIndex); + } + + /** + * Adds a set of attributes to a subrange of the string. + * + * @param attributes The attributes to be added to the string. + * @param beginIndex Index of the first character of the range. + * @param endIndex Index of the character following the last character of the + * range. + * @throws NullPointerException if {@code attributes} is null. + * @throws IllegalArgumentException if beginIndex is less than 0, endIndex is + * greater than the length of the string, or + * beginIndex and endIndex together don't + * define a non-empty subrange of the string + * and the attributes parameter is not an empty + * Map. + */ + public void addAttributes(Map attributes, int beginIndex, int endIndex) { + if (attributes == null) { + throw new NullPointerException(); + } + + if (beginIndex < 0 || endIndex > length() || beginIndex > endIndex) { + throw new IllegalArgumentException("Invalid substring range"); + } + if (beginIndex == endIndex) { + if (attributes.isEmpty()) + return; + throw new IllegalArgumentException("Can't add attribute to 0-length text"); + } + + // make sure we have run attribute data vectors + if (runCount == 0) { + createRunAttributeDataVectors(); + } + + // break up runs if necessary + int beginRunIndex = ensureRunBreak(beginIndex); + int endRunIndex = ensureRunBreak(endIndex); + + Iterator> iterator = attributes.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + addAttributeRunData(entry.getKey(), entry.getValue(), beginRunIndex, endRunIndex); + } + } + + private synchronized void addAttributeImpl(Attribute attribute, Object value, int beginIndex, int endIndex) { + + // make sure we have run attribute data vectors + if (runCount == 0) { + createRunAttributeDataVectors(); + } + + // break up runs if necessary + int beginRunIndex = ensureRunBreak(beginIndex); + int endRunIndex = ensureRunBreak(endIndex); + + addAttributeRunData(attribute, value, beginRunIndex, endRunIndex); + } + + private final void createRunAttributeDataVectors() { + // use temporary variables so things remain consistent in case of an exception + int[] newRunStarts = new int[INITIAL_CAPACITY]; + + @SuppressWarnings("unchecked") + Vector[] newRunAttributes = (Vector[]) new Vector[INITIAL_CAPACITY]; + + @SuppressWarnings("unchecked") + Vector[] newRunAttributeValues = (Vector[]) new Vector[INITIAL_CAPACITY]; + + runStarts = newRunStarts; + runAttributes = newRunAttributes; + runAttributeValues = newRunAttributeValues; + runCount = 1; // assume initial run starting at index 0 + } + + // ensure there's a run break at offset, return the index of the run + private final int ensureRunBreak(int offset) { + return ensureRunBreak(offset, true); + } + + /** + * Ensures there is a run break at offset, returning the index of the run. If + * this results in splitting a run, two things can happen: + *
    + *
  • If copyAttrs is true, the attributes from the existing run will be placed + * in both of the newly created runs. + *
  • If copyAttrs is false, the attributes from the existing run will NOT be + * copied to the run to the right (>= offset) of the break, but will exist on + * the run to the left (< offset). + *
+ */ + private final int ensureRunBreak(int offset, boolean copyAttrs) { + if (offset == length()) { + return runCount; + } + + // search for the run index where this offset should be + int runIndex = 0; + while (runIndex < runCount && runStarts[runIndex] < offset) { + runIndex++; + } + + // if the offset is at a run start already, we're done + if (runIndex < runCount && runStarts[runIndex] == offset) { + return runIndex; + } + + // we'll have to break up a run + // first, make sure we have enough space in our arrays + int currentCapacity = runStarts.length; + if (runCount == currentCapacity) { + // We need to resize - we grow capacity by 25%. + int newCapacity = currentCapacity + (currentCapacity >> 2); + + // use temporary variables so things remain consistent in case of an exception + int[] newRunStarts = Arrays.copyOf(runStarts, newCapacity); + Vector[] newRunAttributes = Arrays.copyOf(runAttributes, newCapacity); + Vector[] newRunAttributeValues = Arrays.copyOf(runAttributeValues, newCapacity); + + runStarts = newRunStarts; + runAttributes = newRunAttributes; + runAttributeValues = newRunAttributeValues; + } + + // make copies of the attribute information of the old run that the new one used + // to be part of + // use temporary variables so things remain consistent in case of an exception + Vector newRunAttributes = null; + Vector newRunAttributeValues = null; + + if (copyAttrs) { + Vector oldRunAttributes = runAttributes[runIndex - 1]; + Vector oldRunAttributeValues = runAttributeValues[runIndex - 1]; + if (oldRunAttributes != null) { + newRunAttributes = new Vector<>(oldRunAttributes); + } + if (oldRunAttributeValues != null) { + newRunAttributeValues = new Vector<>(oldRunAttributeValues); + } + } + + // now actually break up the run + runCount++; + for (int i = runCount - 1; i > runIndex; i--) { + runStarts[i] = runStarts[i - 1]; + runAttributes[i] = runAttributes[i - 1]; + runAttributeValues[i] = runAttributeValues[i - 1]; + } + runStarts[runIndex] = offset; + runAttributes[runIndex] = newRunAttributes; + runAttributeValues[runIndex] = newRunAttributeValues; + + return runIndex; + } + + // add the attribute attribute/value to all runs where beginRunIndex <= runIndex + // < endRunIndex + private void addAttributeRunData(Attribute attribute, Object value, int beginRunIndex, int endRunIndex) { + + for (int i = beginRunIndex; i < endRunIndex; i++) { + int keyValueIndex = -1; // index of key and value in our vectors; assume we don't have an entry yet + if (runAttributes[i] == null) { + Vector newRunAttributes = new Vector<>(); + Vector newRunAttributeValues = new Vector<>(); + runAttributes[i] = newRunAttributes; + runAttributeValues[i] = newRunAttributeValues; + } else { + // check whether we have an entry already + keyValueIndex = runAttributes[i].indexOf(attribute); + } + + if (keyValueIndex == -1) { + // create new entry + int oldSize = runAttributes[i].size(); + runAttributes[i].addElement(attribute); + try { + runAttributeValues[i].addElement(value); + } catch (Exception e) { + runAttributes[i].setSize(oldSize); + runAttributeValues[i].setSize(oldSize); + } + } else { + // update existing entry + runAttributeValues[i].set(keyValueIndex, value); + } + } + } + + /** + * Creates an AttributedCharacterIterator instance that provides access to the + * entire contents of this string. + * + * @return An iterator providing access to the text and its attributes. + */ + public AttributedCharacterIterator getIterator() { + return getIterator(null, 0, length()); + } + + /** + * Creates an AttributedCharacterIterator instance that provides access to + * selected contents of this string. Information about attributes not listed in + * attributes that the implementor may have need not be made accessible through + * the iterator. If the list is null, all available attribute information should + * be made accessible. + * + * @param attributes a list of attributes that the client is interested in + * @return an iterator providing access to the entire text and its selected + * attributes + */ + public AttributedCharacterIterator getIterator(Attribute[] attributes) { + return getIterator(attributes, 0, length()); + } + + /** + * Creates an AttributedCharacterIterator instance that provides access to + * selected contents of this string. Information about attributes not listed in + * attributes that the implementor may have need not be made accessible through + * the iterator. If the list is null, all available attribute information should + * be made accessible. + * + * @param attributes a list of attributes that the client is interested in + * @param beginIndex the index of the first character + * @param endIndex the index of the character following the last character + * @return an iterator providing access to the text and its attributes + * @throws IllegalArgumentException if beginIndex is less than 0, endIndex is + * greater than the length of the string, or + * beginIndex is greater than endIndex. + */ + public AttributedCharacterIterator getIterator(Attribute[] attributes, int beginIndex, int endIndex) { + return new AttributedStringIterator(attributes, beginIndex, endIndex); + } + + // all (with the exception of length) reading operations are private, + // since AttributedString instances are accessed through iterators. + + // length is package private so that CharacterIteratorFieldDelegate can + // access it without creating an AttributedCharacterIterator. + int length() { + return text.length(); + } + + private char charAt(int index) { + return text.charAt(index); + } + + private synchronized Object getAttribute(Attribute attribute, int runIndex) { + Vector currentRunAttributes = runAttributes[runIndex]; + Vector currentRunAttributeValues = runAttributeValues[runIndex]; + if (currentRunAttributes == null) { + return null; + } + int attributeIndex = currentRunAttributes.indexOf(attribute); + if (attributeIndex != -1) { + return currentRunAttributeValues.elementAt(attributeIndex); + } else { + return null; + } + } + + // gets an attribute value, but returns an annotation only if it's range does + // not extend outside the range beginIndex..endIndex + private Object getAttributeCheckRange(Attribute attribute, int runIndex, int beginIndex, int endIndex) { + Object value = getAttribute(attribute, runIndex); + if (value instanceof Annotation) { + // need to check whether the annotation's range extends outside the iterator's + // range + if (beginIndex > 0) { + int currIndex = runIndex; + int runStart = runStarts[currIndex]; + while (runStart >= beginIndex && valuesMatch(value, getAttribute(attribute, currIndex - 1))) { + currIndex--; + runStart = runStarts[currIndex]; + } + if (runStart < beginIndex) { + // annotation's range starts before iterator's range + return null; + } + } + int textLength = length(); + if (endIndex < textLength) { + int currIndex = runIndex; + int runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength; + while (runLimit <= endIndex && valuesMatch(value, getAttribute(attribute, currIndex + 1))) { + currIndex++; + runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength; + } + if (runLimit > endIndex) { + // annotation's range ends after iterator's range + return null; + } + } + // annotation's range is subrange of iterator's range, + // so we can return the value + } + return value; + } + + // returns whether all specified attributes have equal values in the runs with + // the given indices + private boolean attributeValuesMatch(Set attributes, int runIndex1, int runIndex2) { + Iterator iterator = attributes.iterator(); + while (iterator.hasNext()) { + Attribute key = iterator.next(); + if (!valuesMatch(getAttribute(key, runIndex1), getAttribute(key, runIndex2))) { + return false; + } + } + return true; + } + + // returns whether the two objects are either both null or equal + private static final boolean valuesMatch(Object value1, Object value2) { + if (value1 == null) { + return value2 == null; + } else { + return value1.equals(value2); + } + } + + /** + * Appends the contents of the CharacterIterator iterator into the StringBuffer + * buf. + */ + private final void appendContents(StringBuffer buf, CharacterIterator iterator) { + int index = iterator.getBeginIndex(); + int end = iterator.getEndIndex(); + + while (index < end) { + iterator.setIndex(index++); + buf.append(iterator.current()); + } + } + + /** + * Sets the attributes for the range from offset to the next run break + * (typically the end of the text) to the ones specified in attrs. This is only + * meant to be called from the constructor! + */ + private void setAttributes(Map attrs, int offset) { + if (runCount == 0) { + createRunAttributeDataVectors(); + } + + int index = ensureRunBreak(offset, false); + int size; + + if (attrs != null && (size = attrs.size()) > 0) { + Vector runAttrs = new Vector<>(size); + Vector runValues = new Vector<>(size); + Iterator> iterator = attrs.entrySet().iterator(); + + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + + runAttrs.add(entry.getKey()); + runValues.add(entry.getValue()); + } + runAttributes[index] = runAttrs; + runAttributeValues[index] = runValues; + } + } + + /** + * Returns true if the attributes specified in last and attrs differ. + */ + private static boolean mapsDiffer(Map last, Map attrs) { + if (last == null) { + return (attrs != null && attrs.size() > 0); + } + return (!last.equals(attrs)); + } + + // the iterator class associated with this string class + + private final class AttributedStringIterator implements AttributedCharacterIterator { + + // note on synchronization: + // we don't synchronize on the iterator, assuming that an iterator is only used + // in one thread. + // we do synchronize access to the AttributedString however, since it's more + // likely to be shared between threads. + + // start and end index for our iteration + private int beginIndex; + private int endIndex; + + // attributes that our client is interested in + private Attribute[] relevantAttributes; + + // the current index for our iteration + // invariant: beginIndex <= currentIndex <= endIndex + private int currentIndex; + + // information about the run that includes currentIndex + private int currentRunIndex; + private int currentRunStart; + private int currentRunLimit; + + // constructor + AttributedStringIterator(Attribute[] attributes, int beginIndex, int endIndex) { + + if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) { + throw new IllegalArgumentException("Invalid substring range"); + } + + this.beginIndex = beginIndex; + this.endIndex = endIndex; + this.currentIndex = beginIndex; + updateRunInfo(); + if (attributes != null) { + relevantAttributes = attributes.clone(); + } + } + + // Object methods. See documentation in that class. + + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof AttributedStringIterator)) { + return false; + } + + AttributedStringIterator that = (AttributedStringIterator) obj; + + if (AttributedString.this != that.getString()) + return false; + if (currentIndex != that.currentIndex || beginIndex != that.beginIndex || endIndex != that.endIndex) + return false; + return true; + } + + public int hashCode() { + return text.hashCode() ^ currentIndex ^ beginIndex ^ endIndex; + } + + public Object clone() { + try { + AttributedStringIterator other = (AttributedStringIterator) super.clone(); + return other; + } catch (CloneNotSupportedException e) { + throw new InternalError(e); + } + } + + // CharacterIterator methods. See documentation in that interface. + + public char first() { + return internalSetIndex(beginIndex); + } + + public char last() { + if (endIndex == beginIndex) { + return internalSetIndex(endIndex); + } else { + return internalSetIndex(endIndex - 1); + } + } + + public char current() { + if (currentIndex == endIndex) { + return DONE; + } else { + return charAt(currentIndex); + } + } + + public char next() { + if (currentIndex < endIndex) { + return internalSetIndex(currentIndex + 1); + } else { + return DONE; + } + } + + public char previous() { + if (currentIndex > beginIndex) { + return internalSetIndex(currentIndex - 1); + } else { + return DONE; + } + } + + public char setIndex(int position) { + if (position < beginIndex || position > endIndex) + throw new IllegalArgumentException("Invalid index"); + return internalSetIndex(position); + } + + public int getBeginIndex() { + return beginIndex; + } + + public int getEndIndex() { + return endIndex; + } + + public int getIndex() { + return currentIndex; + } + + // AttributedCharacterIterator methods. See documentation in that interface. + + public int getRunStart() { + return currentRunStart; + } + + public int getRunStart(Attribute attribute) { + if (currentRunStart == beginIndex || currentRunIndex == -1) { + return currentRunStart; + } else { + Object value = getAttribute(attribute); + int runStart = currentRunStart; + int runIndex = currentRunIndex; + while (runStart > beginIndex + && valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex - 1))) { + runIndex--; + runStart = runStarts[runIndex]; + } + if (runStart < beginIndex) { + runStart = beginIndex; + } + return runStart; + } + } + + public int getRunStart(Set attributes) { + if (currentRunStart == beginIndex || currentRunIndex == -1) { + return currentRunStart; + } else { + int runStart = currentRunStart; + int runIndex = currentRunIndex; + while (runStart > beginIndex + && AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex - 1)) { + runIndex--; + runStart = runStarts[runIndex]; + } + if (runStart < beginIndex) { + runStart = beginIndex; + } + return runStart; + } + } + + public int getRunLimit() { + return currentRunLimit; + } + + public int getRunLimit(Attribute attribute) { + if (currentRunLimit == endIndex || currentRunIndex == -1) { + return currentRunLimit; + } else { + Object value = getAttribute(attribute); + int runLimit = currentRunLimit; + int runIndex = currentRunIndex; + while (runLimit < endIndex + && valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex + 1))) { + runIndex++; + runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex; + } + if (runLimit > endIndex) { + runLimit = endIndex; + } + return runLimit; + } + } + + public int getRunLimit(Set attributes) { + if (currentRunLimit == endIndex || currentRunIndex == -1) { + return currentRunLimit; + } else { + int runLimit = currentRunLimit; + int runIndex = currentRunIndex; + while (runLimit < endIndex + && AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex + 1)) { + runIndex++; + runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex; + } + if (runLimit > endIndex) { + runLimit = endIndex; + } + return runLimit; + } + } + + public Map getAttributes() { + if (runAttributes == null || currentRunIndex == -1 || runAttributes[currentRunIndex] == null) { + // ??? would be nice to return null, but current spec doesn't allow it + // returning Hashtable saves AttributeMap from dealing with emptiness + return new Hashtable<>(); + } + return new AttributeMap(currentRunIndex, beginIndex, endIndex); + } + + public Set getAllAttributeKeys() { + // ??? This should screen out attribute keys that aren't relevant to the client + if (runAttributes == null) { + // ??? would be nice to return null, but current spec doesn't allow it + // returning HashSet saves us from dealing with emptiness + return new HashSet<>(); + } + synchronized (AttributedString.this) { + // ??? should try to create this only once, then update if necessary, + // and give callers read-only view + Set keys = new HashSet<>(); + int i = 0; + while (i < runCount) { + if (runStarts[i] < endIndex && (i == runCount - 1 || runStarts[i + 1] > beginIndex)) { + Vector currentRunAttributes = runAttributes[i]; + if (currentRunAttributes != null) { + int j = currentRunAttributes.size(); + while (j-- > 0) { + keys.add(currentRunAttributes.get(j)); + } + } + } + i++; + } + return keys; + } + } + + public Object getAttribute(Attribute attribute) { + int runIndex = currentRunIndex; + if (runIndex < 0) { + return null; + } + return AttributedString.this.getAttributeCheckRange(attribute, runIndex, beginIndex, endIndex); + } + + // internally used methods + + private AttributedString getString() { + return AttributedString.this; + } + + // set the current index, update information about the current run if necessary, + // return the character at the current index + private char internalSetIndex(int position) { + currentIndex = position; + if (position < currentRunStart || position >= currentRunLimit) { + updateRunInfo(); + } + if (currentIndex == endIndex) { + return DONE; + } else { + return charAt(position); + } + } + + // update the information about the current run + private void updateRunInfo() { + if (currentIndex == endIndex) { + currentRunStart = currentRunLimit = endIndex; + currentRunIndex = -1; + } else { + synchronized (AttributedString.this) { + int runIndex = -1; + while (runIndex < runCount - 1 && runStarts[runIndex + 1] <= currentIndex) + runIndex++; + currentRunIndex = runIndex; + if (runIndex >= 0) { + currentRunStart = runStarts[runIndex]; + if (currentRunStart < beginIndex) + currentRunStart = beginIndex; + } else { + currentRunStart = beginIndex; + } + if (runIndex < runCount - 1) { + currentRunLimit = runStarts[runIndex + 1]; + if (currentRunLimit > endIndex) + currentRunLimit = endIndex; + } else { + currentRunLimit = endIndex; + } + } + } + } + + } + + // the map class associated with this string class, giving access to the + // attributes of one run + + private final class AttributeMap extends AbstractMap { + + int runIndex; + int beginIndex; + int endIndex; + + AttributeMap(int runIndex, int beginIndex, int endIndex) { + this.runIndex = runIndex; + this.beginIndex = beginIndex; + this.endIndex = endIndex; + } + + public Set> entrySet() { + HashSet> set = new HashSet<>(); + synchronized (AttributedString.this) { + int size = runAttributes[runIndex].size(); + for (int i = 0; i < size; i++) { + Attribute key = runAttributes[runIndex].get(i); + Object value = runAttributeValues[runIndex].get(i); + if (value instanceof Annotation) { + value = AttributedString.this.getAttributeCheckRange(key, runIndex, beginIndex, endIndex); + if (value == null) { + continue; + } + } + + Map.Entry entry = new AttributeEntry(key, value); + set.add(entry); + } + } + return set; + } + + public Object get(Object key) { + return AttributedString.this.getAttributeCheckRange((Attribute) key, runIndex, beginIndex, endIndex); + } + } +} + +class AttributeEntry implements Map.Entry { + + private Attribute key; + private Object value; + + AttributeEntry(Attribute key, Object value) { + this.key = key; + this.value = value; + } + + public boolean equals(Object o) { + if (!(o instanceof AttributeEntry)) { + return false; + } + AttributeEntry other = (AttributeEntry) o; + return other.key.equals(key) && Objects.equals(other.value, value); + } + + public Attribute getKey() { + return key; + } + + public Object getValue() { + return value; + } + + public Object setValue(Object newValue) { + throw new UnsupportedOperationException(); + } + + public int hashCode() { + return key.hashCode() ^ (value == null ? 0 : value.hashCode()); + } + + public String toString() { + return key.toString() + "=" + value.toString(); + } +} diff --git a/src/main/java/jdk_internal/bidi/Bidi.java b/src/main/java/jdk_internal/bidi/Bidi.java new file mode 100755 index 00000000..8c698bea --- /dev/null +++ b/src/main/java/jdk_internal/bidi/Bidi.java @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * (C) Copyright IBM Corp. 1999-2003 - All Rights Reserved + * + * The original version of this source code and documentation is + * copyrighted and owned by IBM. These materials are provided + * under terms of a License Agreement between IBM and Sun. + * This technology is protected by multiple US and International + * patents. This notice and attribution to IBM may not be removed. + */ + +package jdk_internal.bidi; + +import jdk_internal.bidi.icu.text.BidiBase; + +/** + * This class implements the Unicode Bidirectional Algorithm. + *

+ * A Bidi object provides information on the bidirectional reordering of the + * text used to create it. This is required, for example, to properly display + * Arabic or Hebrew text. These languages are inherently mixed directional, as + * they order numbers from left-to-right while ordering most other text from + * right-to-left. + *

+ * Once created, a Bidi object can be queried to see if the text it represents + * is all left-to-right or all right-to-left. Such objects are very lightweight + * and this text is relatively easy to process. + *

+ * If there are multiple runs of text, information about the runs can be + * accessed by indexing to get the start, limit, and level of a run. The level + * represents both the direction and the 'nesting level' of a directional run. + * Odd levels are right-to-left, while even levels are left-to-right. So for + * example level 0 represents left-to-right text, while level 1 represents + * right-to-left text, and level 2 represents left-to-right text embedded in a + * right-to-left run. + * + * @since 1.4 + */ +public final class Bidi { + + /** Constant indicating base direction is left-to-right. */ + public static final int DIRECTION_LEFT_TO_RIGHT = 0; + + /** Constant indicating base direction is right-to-left. */ + public static final int DIRECTION_RIGHT_TO_LEFT = 1; + + /** + * Constant indicating that the base direction depends on the first strong + * directional character in the text according to the Unicode Bidirectional + * Algorithm. If no strong directional character is present, the base direction + * is left-to-right. + */ + public static final int DIRECTION_DEFAULT_LEFT_TO_RIGHT = -2; + + /** + * Constant indicating that the base direction depends on the first strong + * directional character in the text according to the Unicode Bidirectional + * Algorithm. If no strong directional character is present, the base direction + * is right-to-left. + */ + public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT = -1; + + private BidiBase bidiBase; + + /** + * Create Bidi from the given paragraph of text and base direction. + * + * @param paragraph a paragraph of text + * @param flags a collection of flags that control the algorithm. The + * algorithm understands the flags DIRECTION_LEFT_TO_RIGHT, + * DIRECTION_RIGHT_TO_LEFT, DIRECTION_DEFAULT_LEFT_TO_RIGHT, + * and DIRECTION_DEFAULT_RIGHT_TO_LEFT. Other values are + * reserved. + */ + public Bidi(String paragraph, int flags) { + if (paragraph == null) { + throw new IllegalArgumentException("paragraph is null"); + } + + bidiBase = new BidiBase(paragraph.toCharArray(), 0, null, 0, paragraph.length(), flags); + } + + /** + * Create Bidi from the given paragraph of text. + *

+ * The RUN_DIRECTION attribute in the text, if present, determines the base + * direction (left-to-right or right-to-left). If not present, the base + * direction is computes using the Unicode Bidirectional Algorithm, defaulting + * to left-to-right if there are no strong directional characters in the text. + * This attribute, if present, must be applied to all the text in the paragraph. + *

+ * The BIDI_EMBEDDING attribute in the text, if present, represents embedding + * level information. Negative values from -1 to -62 indicate overrides at the + * absolute value of the level. Positive values from 1 to 62 indicate + * embeddings. Where values are zero or not defined, the base embedding level as + * determined by the base direction is assumed. + *

+ * The NUMERIC_SHAPING attribute in the text, if present, converts European + * digits to other decimal digits before running the bidi algorithm. This + * attribute, if present, must be applied to all the text in the paragraph. + * + * @param paragraph a paragraph of text with optional character and paragraph + * attribute information + * + * @see java.awt.font.TextAttribute#BIDI_EMBEDDING + * @see java.awt.font.TextAttribute#NUMERIC_SHAPING + * @see java.awt.font.TextAttribute#RUN_DIRECTION + */ + public Bidi(AttributedCharacterIterator paragraph) { + if (paragraph == null) { + throw new IllegalArgumentException("paragraph is null"); + } + + bidiBase = new BidiBase(0, 0); + bidiBase.setPara(paragraph); + } + + /** + * Create Bidi from the given text, embedding, and direction information. The + * embeddings array may be null. If present, the values represent embedding + * level information. Negative values from -1 to -61 indicate overrides at the + * absolute value of the level. Positive values from 1 to 61 indicate + * embeddings. Where values are zero, the base embedding level as determined by + * the base direction is assumed. + * + * @param text an array containing the paragraph of text to process. + * @param textStart the index into the text array of the start of the + * paragraph. + * @param embeddings an array containing embedding values for each + * character in the paragraph. This can be null, in which + * case it is assumed that there is no external embedding + * information. + * @param embStart the index into the embedding array of the start of the + * paragraph. + * @param paragraphLength the length of the paragraph in the text and embeddings + * arrays. + * @param flags a collection of flags that control the algorithm. The + * algorithm understands the flags + * DIRECTION_LEFT_TO_RIGHT, DIRECTION_RIGHT_TO_LEFT, + * DIRECTION_DEFAULT_LEFT_TO_RIGHT, and + * DIRECTION_DEFAULT_RIGHT_TO_LEFT. Other values are + * reserved. + */ + public Bidi(char[] text, int textStart, byte[] embeddings, int embStart, int paragraphLength, int flags) { + if (text == null) { + throw new IllegalArgumentException("text is null"); + } + if (paragraphLength < 0) { + throw new IllegalArgumentException("bad length: " + paragraphLength); + } + if (textStart < 0 || paragraphLength > text.length - textStart) { + throw new IllegalArgumentException( + "bad range: " + textStart + " length: " + paragraphLength + " for text of length: " + text.length); + } + if (embeddings != null && (embStart < 0 || paragraphLength > embeddings.length - embStart)) { + throw new IllegalArgumentException("bad range: " + embStart + " length: " + paragraphLength + + " for embeddings of length: " + text.length); + } + + bidiBase = new BidiBase(text, textStart, embeddings, embStart, paragraphLength, flags); + } + + /** + * Create a Bidi object representing the bidi information on a line of text + * within the paragraph represented by the current Bidi. This call is not + * required if the entire paragraph fits on one line. + * + * @param lineStart the offset from the start of the paragraph to the start of + * the line. + * @param lineLimit the offset from the start of the paragraph to the limit of + * the line. + * @return a {@code Bidi} object + */ + public Bidi createLineBidi(int lineStart, int lineLimit) { + AttributedString astr = new AttributedString(""); + Bidi newBidi = new Bidi(astr.getIterator()); + + return bidiBase.setLine(this, bidiBase, newBidi, newBidi.bidiBase, lineStart, lineLimit); + } + + /** + * Return true if the line is not left-to-right or right-to-left. This means it + * either has mixed runs of left-to-right and right-to-left text, or the base + * direction differs from the direction of the only run of text. + * + * @return true if the line is not left-to-right or right-to-left. + */ + public boolean isMixed() { + return bidiBase.isMixed(); + } + + /** + * Return true if the line is all left-to-right text and the base direction is + * left-to-right. + * + * @return true if the line is all left-to-right text and the base direction is + * left-to-right + */ + public boolean isLeftToRight() { + return bidiBase.isLeftToRight(); + } + + /** + * Return true if the line is all right-to-left text, and the base direction is + * right-to-left. + * + * @return true if the line is all right-to-left text, and the base direction is + * right-to-left + */ + public boolean isRightToLeft() { + return bidiBase.isRightToLeft(); + } + + /** + * Return the length of text in the line. + * + * @return the length of text in the line + */ + public int getLength() { + return bidiBase.getLength(); + } + + /** + * Return true if the base direction is left-to-right. + * + * @return true if the base direction is left-to-right + */ + public boolean baseIsLeftToRight() { + return bidiBase.baseIsLeftToRight(); + } + + /** + * Return the base level (0 if left-to-right, 1 if right-to-left). + * + * @return the base level + */ + public int getBaseLevel() { + return bidiBase.getParaLevel(); + } + + /** + * Return the resolved level of the character at offset. If offset is + * {@literal <} 0 or ≥ the length of the line, return the base direction + * level. + * + * @param offset the index of the character for which to return the level + * @return the resolved level of the character at offset + */ + public int getLevelAt(int offset) { + return bidiBase.getLevelAt(offset); + } + + /** + * Return the number of level runs. + * + * @return the number of level runs + */ + public int getRunCount() { + return bidiBase.countRuns(); + } + + /** + * Return the level of the nth logical run in this line. + * + * @param run the index of the run, between 0 and {@code getRunCount()} + * @return the level of the run + */ + public int getRunLevel(int run) { + return bidiBase.getRunLevel(run); + } + + /** + * Return the index of the character at the start of the nth logical run in this + * line, as an offset from the start of the line. + * + * @param run the index of the run, between 0 and {@code getRunCount()} + * @return the start of the run + */ + public int getRunStart(int run) { + return bidiBase.getRunStart(run); + } + + /** + * Return the index of the character past the end of the nth logical run in this + * line, as an offset from the start of the line. For example, this will return + * the length of the line for the last run on the line. + * + * @param run the index of the run, between 0 and {@code getRunCount()} + * @return limit the limit of the run + */ + public int getRunLimit(int run) { + return bidiBase.getRunLimit(run); + } + + /** + * Return true if the specified text requires bidi analysis. If this returns + * false, the text will display left-to-right. Clients can then avoid + * constructing a Bidi object. Text in the Arabic Presentation Forms area of + * Unicode is presumed to already be shaped and ordered for display, and so will + * not cause this function to return true. + * + * @param text the text containing the characters to test + * @param start the start of the range of characters to test + * @param limit the limit of the range of characters to test + * @return true if the range of characters requires bidi analysis + */ + public static boolean requiresBidi(char[] text, int start, int limit) { + return BidiBase.requiresBidi(text, start, limit); + } + + /** + * Reorder the objects in the array into visual order based on their levels. + * This is a utility function to use when you have a collection of objects + * representing runs of text in logical order, each run containing text at a + * single level. The elements at {@code index} from {@code objectStart} up to + * {@code objectStart + count} in the objects array will be reordered into + * visual order assuming each run of text has the level indicated by the + * corresponding element in the levels array (at + * {@code index - objectStart + levelStart}). + * + * @param levels an array representing the bidi level of each object + * @param levelStart the start position in the levels array + * @param objects the array of objects to be reordered into visual order + * @param objectStart the start position in the objects array + * @param count the number of objects to reorder + */ + public static void reorderVisually(byte[] levels, int levelStart, Object[] objects, int objectStart, int count) { + BidiBase.reorderVisually(levels, levelStart, objects, objectStart, count); + } + + /** + * Display the bidi internal state, used in debugging. + */ + public String toString() { + return bidiBase.toString(); + } + +} diff --git a/src/main/java/jdk_internal/bidi/CharacterIterator.java b/src/main/java/jdk_internal/bidi/CharacterIterator.java new file mode 100755 index 00000000..68312844 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/CharacterIterator.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved + * + * The original version of this source code and documentation + * is copyrighted and owned by Taligent, Inc., a wholly-owned + * subsidiary of IBM. These materials are provided under terms + * of a License Agreement between Taligent and Sun. This technology + * is protected by multiple US and International patents. + * + * This notice and attribution to Taligent may not be removed. + * Taligent is a registered trademark of Taligent, Inc. + * + */ + +package jdk_internal.bidi; + +/** + * This interface defines a protocol for bidirectional iteration over text. The + * iterator iterates over a bounded sequence of characters. Characters are + * indexed with values beginning with the value returned by getBeginIndex() and + * continuing through the value returned by getEndIndex()-1. + *

+ * Iterators maintain a current character index, whose valid range is from + * getBeginIndex() to getEndIndex(); the value getEndIndex() is included to + * allow handling of zero-length text ranges and for historical reasons. The + * current index can be retrieved by calling getIndex() and set directly by + * calling setIndex(), first(), and last(). + *

+ * The methods previous() and next() are used for iteration. They return DONE if + * they would move outside the range from getBeginIndex() to getEndIndex() -1, + * signaling that the iterator has reached the end of the sequence. DONE is also + * returned by other methods to indicate that the current index is outside this + * range. + * + *

+ * Examples: + *

+ * + * Traverse the text from start to finish + * + *

{@code
+ * public void traverseForward(CharacterIterator iter) {
+ * 	for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
+ * 		processChar(c);
+ * 	}
+ * }
+ * }
+ * + * Traverse the text backwards, from end to start + * + *
{@code
+ * public void traverseBackward(CharacterIterator iter) {
+ * 	for (char c = iter.last(); c != CharacterIterator.DONE; c = iter.previous()) {
+ * 		processChar(c);
+ * 	}
+ * }
+ * }
+ * + * Traverse both forward and backward from a given position in the text. Calls + * to notBoundary() in this example represents some additional stopping + * criteria. + * + *
{@code
+ * public void traverseOut(CharacterIterator iter, int pos) {
+ * 	for (char c = iter.setIndex(pos); c != CharacterIterator.DONE && notBoundary(c); c = iter.next()) {
+ * 	}
+ * 	int end = iter.getIndex();
+ * 	for (char c = iter.setIndex(pos); c != CharacterIterator.DONE && notBoundary(c); c = iter.previous()) {
+ * 	}
+ * 	int start = iter.getIndex();
+ * 	processSection(start, end);
+ * }
+ * }
+ * + * @since 1.1 + * @see StringCharacterIterator + * @see AttributedCharacterIterator + */ + +public interface CharacterIterator extends Cloneable { + + /** + * Constant that is returned when the iterator has reached either the end or the + * beginning of the text. The value is '\\uFFFF', the "not a character" value + * which should not occur in any valid Unicode string. + */ + public static final char DONE = '\uFFFF'; + + /** + * Sets the position to getBeginIndex() and returns the character at that + * position. + * + * @return the first character in the text, or DONE if the text is empty + * @see #getBeginIndex() + */ + public char first(); + + /** + * Sets the position to getEndIndex()-1 (getEndIndex() if the text is empty) and + * returns the character at that position. + * + * @return the last character in the text, or DONE if the text is empty + * @see #getEndIndex() + */ + public char last(); + + /** + * Gets the character at the current position (as returned by getIndex()). + * + * @return the character at the current position or DONE if the current position + * is off the end of the text. + * @see #getIndex() + */ + public char current(); + + /** + * Increments the iterator's index by one and returns the character at the new + * index. If the resulting index is greater or equal to getEndIndex(), the + * current index is reset to getEndIndex() and a value of DONE is returned. + * + * @return the character at the new position or DONE if the new position is off + * the end of the text range. + */ + public char next(); + + /** + * Decrements the iterator's index by one and returns the character at the new + * index. If the current index is getBeginIndex(), the index remains at + * getBeginIndex() and a value of DONE is returned. + * + * @return the character at the new position or DONE if the current position is + * equal to getBeginIndex(). + */ + public char previous(); + + /** + * Sets the position to the specified position in the text and returns that + * character. + * + * @param position the position within the text. Valid values range from + * getBeginIndex() to getEndIndex(). An IllegalArgumentException + * is thrown if an invalid value is supplied. + * @return the character at the specified position or DONE if the specified + * position is equal to getEndIndex() + */ + public char setIndex(int position); + + /** + * Returns the start index of the text. + * + * @return the index at which the text begins. + */ + public int getBeginIndex(); + + /** + * Returns the end index of the text. This index is the index of the first + * character following the end of the text. + * + * @return the index after the last character in the text + */ + public int getEndIndex(); + + /** + * Returns the current index. + * + * @return the current index. + */ + public int getIndex(); + + /** + * Create a copy of this iterator + * + * @return A copy of this + */ + public Object clone(); + +} diff --git a/src/main/java/jdk_internal/bidi/Normalizer.java b/src/main/java/jdk_internal/bidi/Normalizer.java new file mode 100755 index 00000000..8029bd38 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/Normalizer.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* + */ + +package jdk_internal.bidi; + +import jdk_internal.bidi.icu.text.NormalizerBase; + +/** + * This class provides the method {@code normalize} which transforms Unicode + * text into an equivalent composed or decomposed form, allowing for easier + * sorting and searching of text. The {@code normalize} method supports the + * standard normalization forms described in + * Unicode Standard Annex #15 + * — Unicode Normalization Forms. + *

+ * Characters with accents or other adornments can be encoded in several + * different ways in Unicode. For example, take the character A-acute. In + * Unicode, this can be encoded as a single character (the "composed" form): + * + *

+ *      U+00C1    LATIN CAPITAL LETTER A WITH ACUTE
+ * 
+ * + * or as two separate characters (the "decomposed" form): + * + *
+ *      U+0041    LATIN CAPITAL LETTER A
+ *      U+0301    COMBINING ACUTE ACCENT
+ * 
+ * + * To a user of your program, however, both of these sequences should be treated + * as the same "user-level" character "A with acute accent". When you are + * searching or comparing text, you must ensure that these two sequences are + * treated as equivalent. In addition, you must handle characters with more than + * one accent. Sometimes the order of a character's combining accents is + * significant, while in other cases accent sequences in different orders are + * really equivalent. + *

+ * Similarly, the string "ffi" can be encoded as three separate letters: + * + *

+ *      U+0066    LATIN SMALL LETTER F
+ *      U+0066    LATIN SMALL LETTER F
+ *      U+0069    LATIN SMALL LETTER I
+ * 
+ * + * or as the single character + * + *
+ *      U+FB03    LATIN SMALL LIGATURE FFI
+ * 
+ * + * The ffi ligature is not a distinct semantic character, and strictly speaking + * it shouldn't be in Unicode at all, but it was included for compatibility with + * existing character sets that already provided it. The Unicode standard + * identifies such characters by giving them "compatibility" decompositions into + * the corresponding semantic characters. When sorting and searching, you will + * often want to use these mappings. + *

+ * The {@code normalize} method helps solve these problems by transforming text + * into the canonical composed and decomposed forms as shown in the first + * example above. In addition, you can have it perform compatibility + * decompositions so that you can treat compatibility characters the same as + * their equivalents. Finally, the {@code normalize} method rearranges accents + * into the proper canonical order, so that you do not have to worry about + * accent rearrangement on your own. + *

+ * The W3C generally recommends to exchange texts in NFC. Note also that most + * legacy character encodings use only precomposed forms and often do not encode + * any combining marks by themselves. For conversion to such character encodings + * the Unicode text needs to be normalized to NFC. For more usage examples, see + * the Unicode Standard Annex. + * + * @since 1.6 + */ +public final class Normalizer { + + private Normalizer() { + }; + + /** + * This enum provides constants of the four Unicode normalization forms that are + * described in Unicode + * Standard Annex #15 — Unicode Normalization Forms and two methods to + * access them. + * + * @since 1.6 + */ + public static enum Form { + + /** + * Canonical decomposition. + */ + NFD, + + /** + * Canonical decomposition, followed by canonical composition. + */ + NFC, + + /** + * Compatibility decomposition. + */ + NFKD, + + /** + * Compatibility decomposition, followed by canonical composition. + */ + NFKC + } + + /** + * Normalize a sequence of char values. The sequence will be normalized + * according to the specified normalization form. + * + * @param src The sequence of char values to normalize. + * @param form The normalization form; one of + * {@link java.text.Normalizer.Form#NFC}, + * {@link java.text.Normalizer.Form#NFD}, + * {@link java.text.Normalizer.Form#NFKC}, + * {@link java.text.Normalizer.Form#NFKD} + * @return The normalized String + * @throws NullPointerException If {@code src} or {@code form} is null. + */ + public static String normalize(CharSequence src, Form form) { + return NormalizerBase.normalize(src.toString(), form); + } + + /** + * Determines if the given sequence of char values is normalized. + * + * @param src The sequence of char values to be checked. + * @param form The normalization form; one of + * {@link java.text.Normalizer.Form#NFC}, + * {@link java.text.Normalizer.Form#NFD}, + * {@link java.text.Normalizer.Form#NFKC}, + * {@link java.text.Normalizer.Form#NFKD} + * @return true if the sequence of char values is normalized; false otherwise. + * @throws NullPointerException If {@code src} or {@code form} is null. + */ + public static boolean isNormalized(CharSequence src, Form form) { + return NormalizerBase.isNormalized(src.toString(), form); + } +} diff --git a/src/main/java/jdk_internal/bidi/NumericShaper.java b/src/main/java/jdk_internal/bidi/NumericShaper.java new file mode 100755 index 00000000..a3f5f803 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/NumericShaper.java @@ -0,0 +1,1351 @@ +/* + * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk_internal.bidi; + +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.util.Arrays; +import java.util.Comparator; +import java.util.EnumSet; +import java.util.Set; + +/** + * The {@code NumericShaper} class is used to convert Latin-1 (European) digits + * to other Unicode decimal digits. Users of this class will primarily be people + * who wish to present data using national digit shapes, but find it more + * convenient to represent the data internally using Latin-1 (European) digits. + * This does not interpret the deprecated numeric shape selector character + * (U+206E). + *

+ * Instances of {@code NumericShaper} are typically applied as attributes to + * text with the {@link TextAttribute#NUMERIC_SHAPING NUMERIC_SHAPING} attribute + * of the {@code TextAttribute} class. For example, this code snippet causes a + * {@code TextLayout} to shape European digits to Arabic in an Arabic + * context:
+ *

+ * + *
+ * Map map = new HashMap();
+ * map.put(TextAttribute.NUMERIC_SHAPING,
+ *     NumericShaper.getContextualShaper(NumericShaper.ARABIC));
+ * FontRenderContext frc = ...;
+ * TextLayout layout = new TextLayout(text, map, frc);
+ * layout.draw(g2d, x, y);
+ * 
+ * + *

+ * It is also possible to perform numeric shaping explicitly using instances of + * {@code NumericShaper}, as this code snippet demonstrates:
+ *
+ * + *
+ * char[] text = ...;
+ * // shape all EUROPEAN digits (except zero) to ARABIC digits
+ * NumericShaper shaper = NumericShaper.getShaper(NumericShaper.ARABIC);
+ * shaper.shape(text, start, count);
+ *
+ * // shape European digits to ARABIC digits if preceding text is Arabic, or
+ * // shape European digits to TAMIL digits if preceding text is Tamil, or
+ * // leave European digits alone if there is no preceding text, or
+ * // preceding text is neither Arabic nor Tamil
+ * NumericShaper shaper =
+ *     NumericShaper.getContextualShaper(NumericShaper.ARABIC |
+ *                                         NumericShaper.TAMIL,
+ *                                       NumericShaper.EUROPEAN);
+ * shaper.shape(text, start, count);
+ * 
+ * + *
+ * + *

+ * Bit mask- and enum-based Unicode ranges + *

+ * + *

+ * This class supports two different programming interfaces to represent Unicode + * ranges for script-specific digits: bit mask-based ones, such as + * {@link #ARABIC NumericShaper.ARABIC}, and enum-based ones, such as + * {@link NumericShaper.Range#ARABIC}. Multiple ranges can be specified by ORing + * bit mask-based constants, such as:

+ * + *
+ * NumericShaper.ARABIC | NumericShaper.TAMIL
+ * 
+ * + *
or creating a {@code Set} with the {@link NumericShaper.Range} + * constants, such as:
+ * + *
+ * EnumSet.of(NumericShaper.Range.ARABIC, NumericShaper.Range.TAMIL)
+ * 
+ * + *
The enum-based ranges are a super set of the bit mask-based + * ones. + * + *

+ * If the two interfaces are mixed (including serialization), Unicode range + * values are mapped to their counterparts where such mapping is possible, such + * as {@code NumericShaper.Range.ARABIC} from/to {@code NumericShaper.ARABIC}. + * If any unmappable range values are specified, such as + * {@code NumericShaper.Range.BALINESE}, those ranges are ignored. + * + *

+ * Decimal Digits Precedence + *

+ * + *

+ * A Unicode range may have more than one set of decimal digits. If multiple + * decimal digits sets are specified for the same Unicode range, one of the sets + * will take precedence as follows. + * + * + * + * + * + * + * + * + * + * + * + *
NumericShaper constants precedence
Unicode Range + * {@code NumericShaper} Constants + * Precedence
Arabic + * {@link NumericShaper#ARABIC NumericShaper.ARABIC}
+ * {@link NumericShaper#EASTERN_ARABIC NumericShaper.EASTERN_ARABIC} + *
{@link NumericShaper#EASTERN_ARABIC NumericShaper.EASTERN_ARABIC} + *
{@link NumericShaper.Range#ARABIC}
+ * {@link NumericShaper.Range#EASTERN_ARABIC} + *
{@link NumericShaper.Range#EASTERN_ARABIC}
Tai Tham + * {@link NumericShaper.Range#TAI_THAM_HORA}
+ * {@link NumericShaper.Range#TAI_THAM_THAM} + *
{@link NumericShaper.Range#TAI_THAM_THAM}
+ * + * @since 1.4 + */ +public final class NumericShaper implements java.io.Serializable { + + /** + * A {@code NumericShaper.Range} represents a Unicode range of a script having + * its own decimal digits. For example, the {@link NumericShaper.Range#THAI} + * range has the Thai digits, THAI DIGIT ZERO (U+0E50) to THAI DIGIT NINE + * (U+0E59). + * + *

+ * The {@code Range} enum replaces the traditional bit mask-based values (e.g., + * {@link NumericShaper#ARABIC}), and supports more Unicode ranges than the bit + * mask-based ones. For example, the following code using the bit mask: + *

+ * + *
+	 * NumericShaper.getContextualShaper(NumericShaper.ARABIC | NumericShaper.TAMIL, NumericShaper.EUROPEAN);
+	 * 
+ * + *
can be written using this enum as:
+ * + *
+	 * NumericShaper.getContextualShaper(EnumSet.of(NumericShaper.Range.ARABIC, NumericShaper.Range.TAMIL),
+	 * 		NumericShaper.Range.EUROPEAN);
+	 * 
+ * + *
+ * + * @since 1.7 + */ + public static enum Range { + // The order of EUROPEAN to MOGOLIAN must be consistent + // with the bitmask-based constants. + /** + * The Latin (European) range with the Latin (ASCII) digits. + */ + EUROPEAN('\u0030', '\u0000', '\u0300'), + /** + * The Arabic range with the Arabic-Indic digits. + */ + ARABIC('\u0660', '\u0600', '\u0780'), + /** + * The Arabic range with the Eastern Arabic-Indic digits. + */ + EASTERN_ARABIC('\u06f0', '\u0600', '\u0780'), + /** + * The Devanagari range with the Devanagari digits. + */ + DEVANAGARI('\u0966', '\u0900', '\u0980'), + /** + * The Bengali range with the Bengali digits. + */ + BENGALI('\u09e6', '\u0980', '\u0a00'), + /** + * The Gurmukhi range with the Gurmukhi digits. + */ + GURMUKHI('\u0a66', '\u0a00', '\u0a80'), + /** + * The Gujarati range with the Gujarati digits. + */ + GUJARATI('\u0ae6', '\u0b00', '\u0b80'), + /** + * The Oriya range with the Oriya digits. + */ + ORIYA('\u0b66', '\u0b00', '\u0b80'), + /** + * The Tamil range with the Tamil digits. + */ + TAMIL('\u0be6', '\u0b80', '\u0c00'), + /** + * The Telugu range with the Telugu digits. + */ + TELUGU('\u0c66', '\u0c00', '\u0c80'), + /** + * The Kannada range with the Kannada digits. + */ + KANNADA('\u0ce6', '\u0c80', '\u0d00'), + /** + * The Malayalam range with the Malayalam digits. + */ + MALAYALAM('\u0d66', '\u0d00', '\u0d80'), + /** + * The Thai range with the Thai digits. + */ + THAI('\u0e50', '\u0e00', '\u0e80'), + /** + * The Lao range with the Lao digits. + */ + LAO('\u0ed0', '\u0e80', '\u0f00'), + /** + * The Tibetan range with the Tibetan digits. + */ + TIBETAN('\u0f20', '\u0f00', '\u1000'), + /** + * The Myanmar range with the Myanmar digits. + */ + MYANMAR('\u1040', '\u1000', '\u1080'), + /** + * The Ethiopic range with the Ethiopic digits. Ethiopic does not have a decimal + * digit 0 so Latin (European) 0 is used. + */ + ETHIOPIC('\u1369', '\u1200', '\u1380') { + @Override + char getNumericBase() { + return 1; + } + }, + /** + * The Khmer range with the Khmer digits. + */ + KHMER('\u17e0', '\u1780', '\u1800'), + /** + * The Mongolian range with the Mongolian digits. + */ + MONGOLIAN('\u1810', '\u1800', '\u1900'), + // The order of EUROPEAN to MOGOLIAN must be consistent + // with the bitmask-based constants. + + /** + * The N'Ko range with the N'Ko digits. + */ + NKO('\u07c0', '\u07c0', '\u0800'), + /** + * The Myanmar range with the Myanmar Shan digits. + */ + MYANMAR_SHAN('\u1090', '\u1000', '\u10a0'), + /** + * The Limbu range with the Limbu digits. + */ + LIMBU('\u1946', '\u1900', '\u1950'), + /** + * The New Tai Lue range with the New Tai Lue digits. + */ + NEW_TAI_LUE('\u19d0', '\u1980', '\u19e0'), + /** + * The Balinese range with the Balinese digits. + */ + BALINESE('\u1b50', '\u1b00', '\u1b80'), + /** + * The Sundanese range with the Sundanese digits. + */ + SUNDANESE('\u1bb0', '\u1b80', '\u1bc0'), + /** + * The Lepcha range with the Lepcha digits. + */ + LEPCHA('\u1c40', '\u1c00', '\u1c50'), + /** + * The Ol Chiki range with the Ol Chiki digits. + */ + OL_CHIKI('\u1c50', '\u1c50', '\u1c80'), + /** + * The Vai range with the Vai digits. + */ + VAI('\ua620', '\ua500', '\ua640'), + /** + * The Saurashtra range with the Saurashtra digits. + */ + SAURASHTRA('\ua8d0', '\ua880', '\ua8e0'), + /** + * The Kayah Li range with the Kayah Li digits. + */ + KAYAH_LI('\ua900', '\ua900', '\ua930'), + /** + * The Cham range with the Cham digits. + */ + CHAM('\uaa50', '\uaa00', '\uaa60'), + /** + * The Tai Tham Hora range with the Tai Tham Hora digits. + */ + TAI_THAM_HORA('\u1a80', '\u1a20', '\u1ab0'), + /** + * The Tai Tham Tham range with the Tai Tham Tham digits. + */ + TAI_THAM_THAM('\u1a90', '\u1a20', '\u1ab0'), + /** + * The Javanese range with the Javanese digits. + */ + JAVANESE('\ua9d0', '\ua980', '\ua9e0'), + /** + * The Meetei Mayek range with the Meetei Mayek digits. + */ + MEETEI_MAYEK('\uabf0', '\uabc0', '\uac00'), + /** + * The Sinhala range with the Sinhala digits. + * + * @since 9 + */ + SINHALA('\u0de6', '\u0d80', '\u0e00'), + /** + * The Myanmar Extended-B range with the Myanmar Tai Laing digits. + * + * @since 9 + */ + MYANMAR_TAI_LAING('\ua9f0', '\ua9e0', '\uaa00'); + + private static int toRangeIndex(Range script) { + int index = script.ordinal(); + return index < NUM_KEYS ? index : -1; + } + + private static Range indexToRange(int index) { + return index < NUM_KEYS ? Range.values()[index] : null; + } + + private static int toRangeMask(Set ranges) { + int m = 0; + for (Range range : ranges) { + int index = range.ordinal(); + if (index < NUM_KEYS) { + m |= 1 << index; + } + } + return m; + } + + private static Set maskToRangeSet(int mask) { + Set set = EnumSet.noneOf(Range.class); + Range[] a = Range.values(); + for (int i = 0; i < NUM_KEYS; i++) { + if ((mask & (1 << i)) != 0) { + set.add(a[i]); + } + } + return set; + } + + // base character of range digits + private final int base; + // Unicode range + private final int start, // inclusive + end; // exclusive + + private Range(int base, int start, int end) { + this.base = base - ('0' + getNumericBase()); + this.start = start; + this.end = end; + } + + private int getDigitBase() { + return base; + } + + char getNumericBase() { + return 0; + } + + private boolean inRange(int c) { + return start <= c && c < end; + } + } + + /** index of context for contextual shaping - values range from 0 to 18 */ + private int key; + + /** + * flag indicating whether to shape contextually (high bit) and which digit + * ranges to shape (bits 0-18) + */ + private int mask; + + /** + * The context {@code Range} for contextual shaping or the {@code + * Range} for non-contextual shaping. {@code null} for the bit mask-based API. + * + * @since 1.7 + */ + private Range shapingRange; + + /** + * {@code Set} indicating which Unicode ranges to shape. {@code null} for + * the bit mask-based API. + */ + private transient Set rangeSet; + + /** + * rangeSet.toArray() value. Sorted by Range.base when the number of elements is + * greater than BSEARCH_THRESHOLD. + */ + private transient Range[] rangeArray; + + /** + * If more than BSEARCH_THRESHOLD ranges are specified, binary search is used. + */ + private static final int BSEARCH_THRESHOLD = 3; + + /** + * Use serialVersionUID from JDK 1.7 for interoperability. + */ + private static final long serialVersionUID = -8022764705923730308L; + + /** + * Identifies the Latin-1 (European) and extended range, and Latin-1 (European) + * decimal base. + */ + public static final int EUROPEAN = 1 << 0; + + /** Identifies the ARABIC range and decimal base. */ + public static final int ARABIC = 1 << 1; + + /** Identifies the ARABIC range and ARABIC_EXTENDED decimal base. */ + public static final int EASTERN_ARABIC = 1 << 2; + + /** Identifies the DEVANAGARI range and decimal base. */ + public static final int DEVANAGARI = 1 << 3; + + /** Identifies the BENGALI range and decimal base. */ + public static final int BENGALI = 1 << 4; + + /** Identifies the GURMUKHI range and decimal base. */ + public static final int GURMUKHI = 1 << 5; + + /** Identifies the GUJARATI range and decimal base. */ + public static final int GUJARATI = 1 << 6; + + /** Identifies the ORIYA range and decimal base. */ + public static final int ORIYA = 1 << 7; + + /** Identifies the TAMIL range and decimal base. */ + // TAMIL DIGIT ZERO was added in Unicode 4.1 + public static final int TAMIL = 1 << 8; + + /** Identifies the TELUGU range and decimal base. */ + public static final int TELUGU = 1 << 9; + + /** Identifies the KANNADA range and decimal base. */ + public static final int KANNADA = 1 << 10; + + /** Identifies the MALAYALAM range and decimal base. */ + public static final int MALAYALAM = 1 << 11; + + /** Identifies the THAI range and decimal base. */ + public static final int THAI = 1 << 12; + + /** Identifies the LAO range and decimal base. */ + public static final int LAO = 1 << 13; + + /** Identifies the TIBETAN range and decimal base. */ + public static final int TIBETAN = 1 << 14; + + /** Identifies the MYANMAR range and decimal base. */ + public static final int MYANMAR = 1 << 15; + + /** Identifies the ETHIOPIC range and decimal base. */ + public static final int ETHIOPIC = 1 << 16; + + /** Identifies the KHMER range and decimal base. */ + public static final int KHMER = 1 << 17; + + /** Identifies the MONGOLIAN range and decimal base. */ + public static final int MONGOLIAN = 1 << 18; + + /** + * Identifies all ranges, for full contextual shaping. + * + *

+ * This constant specifies all of the bit mask-based ranges. Use + * {@code EnumSet.allOf(NumericShaper.Range.class)} to specify all of the + * enum-based ranges. + */ + public static final int ALL_RANGES = 0x0007ffff; + + private static final int EUROPEAN_KEY = 0; + private static final int ARABIC_KEY = 1; + private static final int EASTERN_ARABIC_KEY = 2; + private static final int DEVANAGARI_KEY = 3; + private static final int BENGALI_KEY = 4; + private static final int GURMUKHI_KEY = 5; + private static final int GUJARATI_KEY = 6; + private static final int ORIYA_KEY = 7; + private static final int TAMIL_KEY = 8; + private static final int TELUGU_KEY = 9; + private static final int KANNADA_KEY = 10; + private static final int MALAYALAM_KEY = 11; + private static final int THAI_KEY = 12; + private static final int LAO_KEY = 13; + private static final int TIBETAN_KEY = 14; + private static final int MYANMAR_KEY = 15; + private static final int ETHIOPIC_KEY = 16; + private static final int KHMER_KEY = 17; + private static final int MONGOLIAN_KEY = 18; + + private static final int NUM_KEYS = MONGOLIAN_KEY + 1; // fixed + + private static final int CONTEXTUAL_MASK = 1 << 31; + + private static final char[] bases = { '\u0030' - '\u0030', // EUROPEAN + '\u0660' - '\u0030', // ARABIC-INDIC + '\u06f0' - '\u0030', // EXTENDED ARABIC-INDIC (EASTERN_ARABIC) + '\u0966' - '\u0030', // DEVANAGARI + '\u09e6' - '\u0030', // BENGALI + '\u0a66' - '\u0030', // GURMUKHI + '\u0ae6' - '\u0030', // GUJARATI + '\u0b66' - '\u0030', // ORIYA + '\u0be6' - '\u0030', // TAMIL - zero was added in Unicode 4.1 + '\u0c66' - '\u0030', // TELUGU + '\u0ce6' - '\u0030', // KANNADA + '\u0d66' - '\u0030', // MALAYALAM + '\u0e50' - '\u0030', // THAI + '\u0ed0' - '\u0030', // LAO + '\u0f20' - '\u0030', // TIBETAN + '\u1040' - '\u0030', // MYANMAR + '\u1369' - '\u0031', // ETHIOPIC - no zero + '\u17e0' - '\u0030', // KHMER + '\u1810' - '\u0030', // MONGOLIAN + }; + + // some ranges adjoin or overlap, rethink if we want to do a binary search on + // this + + private static final char[] contexts = { '\u0000', '\u0300', // 'EUROPEAN' (really latin-1 and extended) + '\u0600', '\u0780', // ARABIC + '\u0600', '\u0780', // EASTERN_ARABIC -- note overlap with arabic + '\u0900', '\u0980', // DEVANAGARI + '\u0980', '\u0a00', // BENGALI + '\u0a00', '\u0a80', // GURMUKHI + '\u0a80', '\u0b00', // GUJARATI + '\u0b00', '\u0b80', // ORIYA + '\u0b80', '\u0c00', // TAMIL + '\u0c00', '\u0c80', // TELUGU + '\u0c80', '\u0d00', // KANNADA + '\u0d00', '\u0d80', // MALAYALAM + '\u0e00', '\u0e80', // THAI + '\u0e80', '\u0f00', // LAO + '\u0f00', '\u1000', // TIBETAN + '\u1000', '\u1080', // MYANMAR + '\u1200', '\u1380', // ETHIOPIC - note missing zero + '\u1780', '\u1800', // KHMER + '\u1800', '\u1900', // MONGOLIAN + '\uffff', }; + + // assume most characters are near each other so probing the cache is + // infrequent, + // and a linear probe is ok. + + private static int ctCache = 0; + private static int ctCacheLimit = contexts.length - 2; + + // warning, synchronize access to this as it modifies state + private static int getContextKey(char c) { + if (c < contexts[ctCache]) { + while (ctCache > 0 && c < contexts[ctCache]) + --ctCache; + } else if (c >= contexts[ctCache + 1]) { + while (ctCache < ctCacheLimit && c >= contexts[ctCache + 1]) + ++ctCache; + } + + // if we're not in a known range, then return EUROPEAN as the range key + return (ctCache & 0x1) == 0 ? (ctCache / 2) : EUROPEAN_KEY; + } + + // cache for the NumericShaper.Range version + private transient volatile Range currentRange = Range.EUROPEAN; + + private Range rangeForCodePoint(final int codepoint) { + if (currentRange.inRange(codepoint)) { + return currentRange; + } + + final Range[] ranges = rangeArray; + if (ranges.length > BSEARCH_THRESHOLD) { + int lo = 0; + int hi = ranges.length - 1; + while (lo <= hi) { + int mid = (lo + hi) / 2; + Range range = ranges[mid]; + if (codepoint < range.start) { + hi = mid - 1; + } else if (codepoint >= range.end) { + lo = mid + 1; + } else { + currentRange = range; + return range; + } + } + } else { + for (int i = 0; i < ranges.length; i++) { + if (ranges[i].inRange(codepoint)) { + return ranges[i]; + } + } + } + return Range.EUROPEAN; + } + + /* + * A range table of strong directional characters (types L, R, AL). Even (left) + * indexes are starts of ranges of non-strong-directional (or undefined) + * characters, odd (right) indexes are starts of ranges of strong directional + * characters. + */ + private static int[] strongTable = { 0x0000, 0x0041, 0x005b, 0x0061, 0x007b, 0x00aa, 0x00ab, 0x00b5, 0x00b6, 0x00ba, + 0x00bb, 0x00c0, 0x00d7, 0x00d8, 0x00f7, 0x00f8, 0x02b9, 0x02bb, 0x02c2, 0x02d0, 0x02d2, 0x02e0, 0x02e5, + 0x02ee, 0x02ef, 0x0370, 0x0374, 0x0376, 0x0378, 0x037a, 0x037e, 0x037f, 0x0380, 0x0386, 0x0387, 0x0388, + 0x038b, 0x038c, 0x038d, 0x038e, 0x03a2, 0x03a3, 0x03f6, 0x03f7, 0x0483, 0x048a, 0x0530, 0x0531, 0x0557, + 0x0559, 0x058a, 0x0590, 0x0591, 0x05be, 0x05bf, 0x05c0, 0x05c1, 0x05c3, 0x05c4, 0x05c6, 0x05c7, 0x05c8, + 0x0600, 0x0608, 0x0609, 0x060b, 0x060c, 0x060d, 0x060e, 0x061b, 0x064b, 0x066d, 0x0670, 0x0671, 0x06d6, + 0x06e5, 0x06e7, 0x06ee, 0x06f0, 0x06fa, 0x0711, 0x0712, 0x0730, 0x074b, 0x07a6, 0x07b1, 0x07eb, 0x07f4, + 0x07f6, 0x07fa, 0x07fd, 0x07fe, 0x0816, 0x081a, 0x081b, 0x0824, 0x0825, 0x0828, 0x0829, 0x082e, 0x0859, + 0x085c, 0x08e3, 0x0903, 0x093a, 0x093b, 0x093c, 0x093d, 0x0941, 0x0949, 0x094d, 0x094e, 0x0951, 0x0958, + 0x0962, 0x0964, 0x0981, 0x0982, 0x0984, 0x0985, 0x098d, 0x098f, 0x0991, 0x0993, 0x09a9, 0x09aa, 0x09b1, + 0x09b2, 0x09b3, 0x09b6, 0x09ba, 0x09bd, 0x09c1, 0x09c7, 0x09c9, 0x09cb, 0x09cd, 0x09ce, 0x09cf, 0x09d7, + 0x09d8, 0x09dc, 0x09de, 0x09df, 0x09e2, 0x09e6, 0x09f2, 0x09f4, 0x09fb, 0x09fc, 0x09fe, 0x0a03, 0x0a04, + 0x0a05, 0x0a0b, 0x0a0f, 0x0a11, 0x0a13, 0x0a29, 0x0a2a, 0x0a31, 0x0a32, 0x0a34, 0x0a35, 0x0a37, 0x0a38, + 0x0a3a, 0x0a3e, 0x0a41, 0x0a59, 0x0a5d, 0x0a5e, 0x0a5f, 0x0a66, 0x0a70, 0x0a72, 0x0a75, 0x0a76, 0x0a73, + 0x0a83, 0x0a84, 0x0a85, 0x0a8e, 0x0a8f, 0x0a92, 0x0a93, 0x0aa9, 0x0aaa, 0x0ab1, 0x0ab2, 0x0ab4, 0x0ab5, + 0x0aba, 0x0abd, 0x0ac1, 0x0ac9, 0x0aca, 0x0acb, 0x0acd, 0x0ad0, 0x0ad1, 0x0ae0, 0x0ae2, 0x0ae6, 0x0af1, + 0x0af9, 0x0afa, 0x0b02, 0x0b04, 0x0b05, 0x0b0d, 0x0b0f, 0x0b11, 0x0b13, 0x0b29, 0x0b2a, 0x0b31, 0x0b32, + 0x0b34, 0x0b35, 0x0b3a, 0x0b3d, 0x0b3f, 0x0b40, 0x0b41, 0x0b47, 0x0b49, 0x0b4b, 0x0b4d, 0x0b57, 0x0b58, + 0x0b5c, 0x0b5e, 0x0b5f, 0x0b62, 0x0b66, 0x0b78, 0x0b83, 0x0b84, 0x0b85, 0x0b8b, 0x0b8e, 0x0b91, 0x0b92, + 0x0b96, 0x0b99, 0x0b9b, 0x0b9c, 0x0b9d, 0x0b9e, 0x0ba0, 0x0ba3, 0x0ba5, 0x0ba8, 0x0bab, 0x0bae, 0x0bba, + 0x0bbe, 0x0bc0, 0x0bc1, 0x0bc3, 0x0bc6, 0x0bc9, 0x0bca, 0x0bcd, 0x0bd0, 0x0bd1, 0x0bd7, 0x0bd8, 0x0be6, + 0x0bf3, 0x0c01, 0x0c04, 0x0c05, 0x0c0d, 0x0c0e, 0x0c11, 0x0c12, 0x0c29, 0x0c2a, 0x0c3a, 0x0c3d, 0x0c3e, + 0x0c41, 0x0c45, 0x0c58, 0x0c5b, 0x0c60, 0x0c62, 0x0c66, 0x0c70, 0x0c7f, 0x0c81, 0x0c82, 0x0c8d, 0x0c8e, + 0x0c91, 0x0c92, 0x0ca9, 0x0caa, 0x0cb4, 0x0cb5, 0x0cba, 0x0cbd, 0x0cc5, 0x0cc6, 0x0cc9, 0x0cca, 0x0ccc, + 0x0cd5, 0x0cd7, 0x0cde, 0x0cdf, 0x0ce0, 0x0ce2, 0x0ce6, 0x0cf0, 0x0cf1, 0x0cf3, 0x0d02, 0x0d04, 0x0d05, + 0x0d0d, 0x0d0e, 0x0d11, 0x0d12, 0x0d3b, 0x0d3d, 0x0d41, 0x0d46, 0x0d49, 0x0d4a, 0x0d4d, 0x0d4e, 0x0d62, + 0x0d66, 0x0d80, 0x0d82, 0x0d84, 0x0d85, 0x0d97, 0x0d9a, 0x0db2, 0x0db3, 0x0dbc, 0x0dbd, 0x0dbe, 0x0dc0, + 0x0dc7, 0x0dcf, 0x0dd2, 0x0dd8, 0x0de0, 0x0de6, 0x0df0, 0x0df2, 0x0df5, 0x0e01, 0x0e31, 0x0e32, 0x0e34, + 0x0e40, 0x0e47, 0x0e4f, 0x0e5c, 0x0e81, 0x0e83, 0x0e84, 0x0e85, 0x0e87, 0x0e89, 0x0e8a, 0x0e8b, 0x0e8d, + 0x0e8e, 0x0e94, 0x0e98, 0x0e99, 0x0ea0, 0x0ea1, 0x0ea4, 0x0ea5, 0x0ea6, 0x0ea7, 0x0ea8, 0x0eaa, 0x0eac, + 0x0ead, 0x0eb1, 0x0eb2, 0x0eb4, 0x0ebd, 0x0ebe, 0x0ec0, 0x0ec5, 0x0ec6, 0x0ec7, 0x0ed0, 0x0eda, 0x0edc, + 0x0ee0, 0x0f00, 0x0f18, 0x0f1a, 0x0f35, 0x0f36, 0x0f37, 0x0f38, 0x0f39, 0x0f3e, 0x0f48, 0x0f49, 0x0f6d, + 0x0f7f, 0x0f80, 0x0f85, 0x0f86, 0x0f88, 0x0f8d, 0x0fbe, 0x0fc6, 0x0fc7, 0x0fcd, 0x0fce, 0x0fdb, 0x1000, + 0x102d, 0x1031, 0x1032, 0x1038, 0x1039, 0x103b, 0x103d, 0x103f, 0x1058, 0x105a, 0x105e, 0x1061, 0x1071, + 0x1075, 0x1082, 0x1083, 0x1085, 0x1087, 0x108d, 0x108e, 0x109d, 0x109e, 0x10c6, 0x10c7, 0x10c8, 0x10cd, + 0x10ce, 0x10d0, 0x1249, 0x124a, 0x124e, 0x1250, 0x1257, 0x1258, 0x1259, 0x125a, 0x125e, 0x1260, 0x1289, + 0x128a, 0x128e, 0x1290, 0x12b1, 0x12b2, 0x12b6, 0x12b8, 0x12bf, 0x12c0, 0x12c1, 0x12c2, 0x12c6, 0x12c8, + 0x12d7, 0x12d8, 0x1311, 0x1312, 0x1316, 0x1318, 0x135b, 0x1360, 0x137d, 0x1380, 0x1390, 0x13a0, 0x13f6, + 0x13f8, 0x13fe, 0x1401, 0x1680, 0x1681, 0x169b, 0x16a0, 0x16f9, 0x1700, 0x170d, 0x170e, 0x1712, 0x1720, + 0x1732, 0x1735, 0x1737, 0x1740, 0x1752, 0x1760, 0x176d, 0x176e, 0x1771, 0x1780, 0x17b4, 0x17b6, 0x17b7, + 0x17be, 0x17c6, 0x17c7, 0x17c9, 0x17d4, 0x17db, 0x17dc, 0x17dd, 0x17e0, 0x17ea, 0x1810, 0x181a, 0x1820, + 0x1879, 0x1884, 0x1885, 0x1887, 0x18a9, 0x18aa, 0x18ab, 0x18b0, 0x18f6, 0x1900, 0x191f, 0x1923, 0x1927, + 0x1929, 0x192c, 0x1930, 0x1932, 0x1933, 0x1939, 0x1946, 0x196e, 0x1970, 0x1975, 0x1980, 0x19ac, 0x19b0, + 0x19ca, 0x19d0, 0x19db, 0x1a00, 0x1a17, 0x1a19, 0x1a1b, 0x1a1e, 0x1a56, 0x1a57, 0x1a58, 0x1a61, 0x1a62, + 0x1a63, 0x1a65, 0x1a6d, 0x1a73, 0x1a80, 0x1a8a, 0x1a90, 0x1a9a, 0x1aa0, 0x1aae, 0x1b04, 0x1b34, 0x1b35, + 0x1b36, 0x1b3b, 0x1b3c, 0x1b3d, 0x1b42, 0x1b43, 0x1b4c, 0x1b50, 0x1b6b, 0x1b74, 0x1b7d, 0x1b82, 0x1ba2, + 0x1ba6, 0x1ba8, 0x1baa, 0x1bab, 0x1bae, 0x1be6, 0x1be7, 0x1be8, 0x1bea, 0x1bed, 0x1bee, 0x1bef, 0x1bf2, + 0x1bf4, 0x1bfc, 0x1c2c, 0x1c34, 0x1c36, 0x1c3b, 0x1c4a, 0x1c4d, 0x1c89, 0x1c90, 0x1cbb, 0x1cbd, 0x1cc8, + 0x1cd3, 0x1cd4, 0x1ce1, 0x1ce2, 0x1ce9, 0x1ced, 0x1cee, 0x1cf4, 0x1cf5, 0x1cf8, 0x1d00, 0x1dc0, 0x1e00, + 0x1f16, 0x1f18, 0x1f1e, 0x1f20, 0x1f46, 0x1f48, 0x1f4e, 0x1f50, 0x1f58, 0x1f59, 0x1f5a, 0x1f5b, 0x1f5c, + 0x1f5d, 0x1f5e, 0x1f5f, 0x1f7e, 0x1f80, 0x1fb5, 0x1fb6, 0x1fbd, 0x1fbe, 0x1fbf, 0x1fc2, 0x1fc5, 0x1fc6, + 0x1fcd, 0x1fd0, 0x1fd4, 0x1fd6, 0x1fdc, 0x1fe0, 0x1fed, 0x1ff2, 0x1ff5, 0x1ff6, 0x1ffd, 0x200e, 0x2010, + 0x2071, 0x2072, 0x207f, 0x2080, 0x2090, 0x209d, 0x2102, 0x2103, 0x2107, 0x2108, 0x210a, 0x2114, 0x2115, + 0x2116, 0x2119, 0x211e, 0x2124, 0x2125, 0x2126, 0x2127, 0x2128, 0x2129, 0x212a, 0x212e, 0x212f, 0x213a, + 0x213c, 0x2140, 0x2145, 0x214a, 0x214e, 0x2150, 0x2160, 0x2189, 0x2336, 0x237b, 0x2395, 0x2396, 0x249c, + 0x24ea, 0x26ac, 0x26ad, 0x2800, 0x2900, 0x2c00, 0x2c2f, 0x2c30, 0x2c5f, 0x2c60, 0x2ce5, 0x2ceb, 0x2cef, + 0x2cf2, 0x2cf4, 0x2d00, 0x2d26, 0x2d27, 0x2d28, 0x2d2d, 0x2d2e, 0x2d30, 0x2d68, 0x2d6f, 0x2d71, 0x2d80, + 0x2d97, 0x2da0, 0x2da7, 0x2da8, 0x2daf, 0x2db0, 0x2db7, 0x2db8, 0x2dbf, 0x2dc0, 0x2dc7, 0x2dc8, 0x2dcf, + 0x2dd0, 0x2dd7, 0x2dd8, 0x2ddf, 0x3005, 0x3008, 0x3021, 0x302a, 0x302e, 0x3030, 0x3031, 0x3036, 0x3038, + 0x303d, 0x3041, 0x3097, 0x309d, 0x30a0, 0x30a1, 0x30fb, 0x30fc, 0x3100, 0x3105, 0x3130, 0x3131, 0x318f, + 0x3190, 0x31bb, 0x31f0, 0x321d, 0x3220, 0x3250, 0x3260, 0x327c, 0x327f, 0x32b1, 0x32c0, 0x32cc, 0x32d0, + 0x32ff, 0x3300, 0x3377, 0x337b, 0x33de, 0x33e0, 0x33ff, 0x3400, 0x4db6, 0x4e00, 0x9ff0, 0xa000, 0xa48d, + 0xa4d0, 0xa60d, 0xa610, 0xa62c, 0xa640, 0xa66f, 0xa680, 0xa69e, 0xa6a0, 0xa6f0, 0xa6f2, 0xa6f8, 0xa722, + 0xa788, 0xa789, 0xa7ba, 0xa7f7, 0xa802, 0xa803, 0xa806, 0xa807, 0xa80b, 0xa80c, 0xa825, 0xa827, 0xa828, + 0xa830, 0xa838, 0xa840, 0xa874, 0xa880, 0xa8c4, 0xa8ce, 0xa8da, 0xa8f2, 0xa8ff, 0xa900, 0xa926, 0xa92e, + 0xa947, 0xa952, 0xa954, 0xa95f, 0xa97d, 0xa983, 0xa9b3, 0xa9b4, 0xa9b6, 0xa9ba, 0xa9bc, 0xa9bd, 0xa9ce, + 0xa9cf, 0xa9da, 0xa9de, 0xa9e5, 0xa9e6, 0xa9ff, 0xaa00, 0xaa29, 0xaa2f, 0xaa31, 0xaa33, 0xaa35, 0xaa40, + 0xaa43, 0xaa44, 0xaa4c, 0xaa4d, 0xaa4e, 0xaa50, 0xaa5a, 0xaa5c, 0xaa7c, 0xaa7d, 0xaab0, 0xaab1, 0xaab2, + 0xaab5, 0xaab7, 0xaab9, 0xaabe, 0xaac0, 0xaac1, 0xaac2, 0xaac3, 0xaadb, 0xaaec, 0xaaee, 0xaaf6, 0xab01, + 0xab07, 0xab09, 0xab0f, 0xab11, 0xab17, 0xab20, 0xab27, 0xab28, 0xab2f, 0xab30, 0xab66, 0xab70, 0xabe5, + 0xabe6, 0xabe8, 0xabe9, 0xabed, 0xabf0, 0xabfa, 0xac00, 0xd7a4, 0xd7b0, 0xd7c7, 0xd7cb, 0xd7fc, 0xe000, + 0xfa6e, 0xfa70, 0xfada, 0xfb00, 0xfb07, 0xfb13, 0xfb18, 0xfb1d, 0xfb1e, 0xfb1f, 0xfb29, 0xfb2a, 0xfd3e, + 0xfd40, 0xfdd0, 0xfdf0, 0xfdfd, 0xfdfe, 0xfe00, 0xfe70, 0xfeff, 0xff21, 0xff3b, 0xff41, 0xff5b, 0xff66, + 0xffbf, 0xffc2, 0xffc8, 0xffca, 0xffd0, 0xffd2, 0xffd8, 0xffda, 0xffdd, 0x10000, 0x1000c, 0x1000d, 0x10027, + 0x10028, 0x1003b, 0x1003c, 0x1003e, 0x1003f, 0x1004e, 0x10050, 0x1005e, 0x10080, 0x100fb, 0x10100, 0x10101, + 0x10102, 0x10103, 0x10107, 0x10134, 0x10137, 0x10140, 0x1018d, 0x1018f, 0x101d0, 0x101fd, 0x10280, 0x1029d, + 0x102a0, 0x102d1, 0x10300, 0x10324, 0x1032d, 0x1034b, 0x10350, 0x10376, 0x10380, 0x1039e, 0x1039f, 0x103c4, + 0x103c8, 0x103d6, 0x10400, 0x1049e, 0x104a0, 0x104aa, 0x104d3, 0x104d4, 0x104d8, 0x104fc, 0x10500, 0x10528, + 0x10530, 0x10564, 0x1056f, 0x10570, 0x10600, 0x10737, 0x10740, 0x10756, 0x10760, 0x10768, 0x10800, 0x1091f, + 0x10920, 0x10a01, 0x10a04, 0x10a05, 0x10a07, 0x10a0c, 0x10a10, 0x10a38, 0x10a3b, 0x10a3f, 0x10a40, 0x10ae5, + 0x10ae7, 0x10b39, 0x10b40, 0x10d00, 0x10d40, 0x10e60, 0x10e7f, 0x10f30, 0x10f70, 0x11001, 0x11002, 0x11038, + 0x11047, 0x1104e, 0x11066, 0x11070, 0x11082, 0x110b3, 0x110b7, 0x110b9, 0x110bb, 0x110c2, 0x110cd, 0x110ce, + 0x110d0, 0x110e9, 0x110f0, 0x110fa, 0x11103, 0x11127, 0x1112c, 0x1112d, 0x11136, 0x11147, 0x11150, 0x11173, + 0x11174, 0x11177, 0x11182, 0x111b6, 0x111bf, 0x111c9, 0x111cd, 0x111ce, 0x111d0, 0x111e0, 0x111e1, 0x111f5, + 0x11200, 0x11212, 0x11213, 0x1122f, 0x11232, 0x11234, 0x11235, 0x11236, 0x11238, 0x1123e, 0x11280, 0x11287, + 0x11288, 0x11289, 0x1128a, 0x1128e, 0x1128f, 0x1129e, 0x1129f, 0x112aa, 0x112b0, 0x112df, 0x112e0, 0x112e3, + 0x112f0, 0x112fa, 0x11302, 0x11304, 0x11305, 0x1130d, 0x1130f, 0x11311, 0x11313, 0x11329, 0x1132a, 0x11331, + 0x11332, 0x11334, 0x11335, 0x1133a, 0x1133d, 0x11340, 0x11341, 0x11345, 0x11347, 0x11349, 0x1134b, 0x1134e, + 0x11350, 0x11351, 0x11357, 0x11358, 0x1135d, 0x11364, 0x11400, 0x11438, 0x11440, 0x11442, 0x11445, 0x11446, + 0x11447, 0x1145a, 0x1145b, 0x1145c, 0x1145d, 0x1145e, 0x11480, 0x114b3, 0x114b9, 0x114ba, 0x114bb, 0x114bf, + 0x114c1, 0x114c2, 0x114c4, 0x114c8, 0x114d0, 0x114da, 0x11580, 0x115b2, 0x115b8, 0x115bc, 0x115be, 0x115bf, + 0x115c1, 0x115dc, 0x11600, 0x11633, 0x1163b, 0x1163d, 0x1163e, 0x1163f, 0x11641, 0x11645, 0x11650, 0x1165a, + 0x11680, 0x116ab, 0x116ac, 0x116ad, 0x116ae, 0x116b0, 0x116b6, 0x116b7, 0x116c0, 0x116ca, 0x11700, 0x1171b, + 0x11720, 0x11722, 0x11726, 0x11727, 0x11730, 0x1182f, 0x11838, 0x11839, 0x1183b, 0x1183c, 0x118a0, 0x118f3, + 0x118ff, 0x11900, 0x11a00, 0x11a01, 0x11a07, 0x11a09, 0x11a0b, 0x11a33, 0x11a3a, 0x11a3b, 0x11a3f, 0x11a47, + 0x11a50, 0x11a51, 0x11a57, 0x11a59, 0x11a5c, 0x11a84, 0x11a86, 0x11a8a, 0x11a97, 0x11a98, 0x11a9a, 0x11aa3, + 0x11ac0, 0x11af9, 0x11c00, 0x11c09, 0x11c0a, 0x11c30, 0x11c3e, 0x11c46, 0x11c50, 0x11c6d, 0x11c70, 0x11c90, + 0x11ca9, 0x11caa, 0x11cb1, 0x11cb2, 0x11cb4, 0x11cb5, 0x11d00, 0x11d07, 0x11d08, 0x11d0a, 0x11d0b, 0x11d31, + 0x11d46, 0x11d47, 0x11d50, 0x11d5a, 0x11d60, 0x11d66, 0x11d67, 0x11d69, 0x11d6a, 0x11d8f, 0x11d93, 0x11d95, + 0x11d96, 0x11d97, 0x11d98, 0x11d99, 0x11da0, 0x11daa, 0x11ee0, 0x11ef3, 0x11ef5, 0x11ef9, 0x12000, 0x1239a, + 0x12400, 0x1246f, 0x12470, 0x12475, 0x12480, 0x12544, 0x13000, 0x1342f, 0x14400, 0x14647, 0x16800, 0x16a39, + 0x16a40, 0x16a5f, 0x16a60, 0x16a6a, 0x16a6e, 0x16a70, 0x16ad0, 0x16aee, 0x16af5, 0x16af6, 0x16b00, 0x16b30, + 0x16b37, 0x16b46, 0x16b50, 0x16b5a, 0x16b5b, 0x16b62, 0x16b63, 0x16b78, 0x16b7d, 0x16b90, 0x16e40, 0x16e9b, + 0x16f00, 0x16f45, 0x16f50, 0x16f7f, 0x16f93, 0x16fa0, 0x16fe0, 0x16fe2, 0x17000, 0x187f2, 0x18800, 0x18af3, + 0x1b000, 0x1b11f, 0x1b170, 0x1b2fc, 0x1bc00, 0x1bc6b, 0x1bc70, 0x1bc7d, 0x1bc80, 0x1bc89, 0x1bc90, 0x1bc9a, + 0x1bc9c, 0x1bc9d, 0x1bc9f, 0x1bca0, 0x1d000, 0x1d0f6, 0x1d100, 0x1d127, 0x1d129, 0x1d167, 0x1d16a, 0x1d173, + 0x1d183, 0x1d185, 0x1d18c, 0x1d1aa, 0x1d1ae, 0x1d1e9, 0x1d2e0, 0x1d2f4, 0x1d360, 0x1d379, 0x1d400, 0x1d455, + 0x1d456, 0x1d49d, 0x1d49e, 0x1d4a0, 0x1d4a2, 0x1d4a3, 0x1d4a5, 0x1d4a7, 0x1d4a9, 0x1d4ad, 0x1d4ae, 0x1d4ba, + 0x1d4bb, 0x1d4bc, 0x1d4bd, 0x1d4c4, 0x1d4c5, 0x1d506, 0x1d507, 0x1d50b, 0x1d50d, 0x1d515, 0x1d516, 0x1d51d, + 0x1d51e, 0x1d53a, 0x1d53b, 0x1d53f, 0x1d540, 0x1d545, 0x1d546, 0x1d547, 0x1d54a, 0x1d551, 0x1d552, 0x1d6a6, + 0x1d6a8, 0x1d6db, 0x1d6dc, 0x1d715, 0x1d716, 0x1d74f, 0x1d750, 0x1d789, 0x1d78a, 0x1d7c3, 0x1d7c4, 0x1d7cc, + 0x1d800, 0x1da00, 0x1da37, 0x1da3b, 0x1da6d, 0x1da75, 0x1da76, 0x1da84, 0x1da85, 0x1da8c, 0x1e800, 0x1e8d0, + 0x1e8d7, 0x1e944, 0x1e94b, 0x1ec70, 0x1ecc0, 0x1ee00, 0x1ef00, 0x1f000, 0x1f110, 0x1f12f, 0x1f130, 0x1f16a, + 0x1f170, 0x1f1ad, 0x1f1e6, 0x1f203, 0x1f210, 0x1f23c, 0x1f240, 0x1f249, 0x1f250, 0x1f252, 0x20000, 0x2a6d7, + 0x2a700, 0x2b735, 0x2b740, 0x2b81e, 0x2b820, 0x2cea2, 0x2ceb0, 0x2ebe1, 0x2f800, 0x2fa1e, 0xf0000, 0xffffe, + 0x100000, 0x10fffe, 0x10ffff // sentinel + }; + + // use a binary search with a cache + + private transient volatile int stCache = 0; + + private boolean isStrongDirectional(char c) { + int cachedIndex = stCache; + if (c < strongTable[cachedIndex]) { + cachedIndex = search(c, strongTable, 0, cachedIndex); + } else if (c >= strongTable[cachedIndex + 1]) { + cachedIndex = search(c, strongTable, cachedIndex + 1, strongTable.length - cachedIndex - 1); + } + boolean val = (cachedIndex & 0x1) == 1; + stCache = cachedIndex; + return val; + } + + private static int getKeyFromMask(int mask) { + int key = 0; + while (key < NUM_KEYS && ((mask & (1 << key)) == 0)) { + ++key; + } + if (key == NUM_KEYS || ((mask & ~(1 << key)) != 0)) { + throw new IllegalArgumentException("invalid shaper: " + Integer.toHexString(mask)); + } + return key; + } + + /** + * Returns a shaper for the provided unicode range. All Latin-1 (EUROPEAN) + * digits are converted to the corresponding decimal unicode digits. + * + * @param singleRange the specified Unicode range + * @return a non-contextual numeric shaper + * @throws IllegalArgumentException if the range is not a single range + */ + public static NumericShaper getShaper(int singleRange) { + int key = getKeyFromMask(singleRange); + return new NumericShaper(key, singleRange); + } + + /** + * Returns a shaper for the provided Unicode range. All Latin-1 (EUROPEAN) + * digits are converted to the corresponding decimal digits of the specified + * Unicode range. + * + * @param singleRange the Unicode range given by a {@link NumericShaper.Range} + * constant. + * @return a non-contextual {@code NumericShaper}. + * @throws NullPointerException if {@code singleRange} is {@code null} + * @since 1.7 + */ + public static NumericShaper getShaper(Range singleRange) { + return new NumericShaper(singleRange, EnumSet.of(singleRange)); + } + + /** + * Returns a contextual shaper for the provided unicode range(s). Latin-1 + * (EUROPEAN) digits are converted to the decimal digits corresponding to the + * range of the preceding text, if the range is one of the provided ranges. + * Multiple ranges are represented by or-ing the values together, such as, + * {@code NumericShaper.ARABIC | NumericShaper.THAI}. The shaper assumes + * EUROPEAN as the starting context, that is, if EUROPEAN digits are encountered + * before any strong directional text in the string, the context is presumed to + * be EUROPEAN, and so the digits will not shape. + * + * @param ranges the specified Unicode ranges + * @return a shaper for the specified ranges + */ + public static NumericShaper getContextualShaper(int ranges) { + ranges |= CONTEXTUAL_MASK; + return new NumericShaper(EUROPEAN_KEY, ranges); + } + + /** + * Returns a contextual shaper for the provided Unicode range(s). The Latin-1 + * (EUROPEAN) digits are converted to the decimal digits corresponding to the + * range of the preceding text, if the range is one of the provided ranges. + * + *

+ * The shaper assumes EUROPEAN as the starting context, that is, if EUROPEAN + * digits are encountered before any strong directional text in the string, the + * context is presumed to be EUROPEAN, and so the digits will not shape. + * + * @param ranges the specified Unicode ranges + * @return a contextual shaper for the specified ranges + * @throws NullPointerException if {@code ranges} is {@code null}. + * @since 1.7 + */ + public static NumericShaper getContextualShaper(Set ranges) { + NumericShaper shaper = new NumericShaper(Range.EUROPEAN, ranges); + shaper.mask = CONTEXTUAL_MASK; + return shaper; + } + + /** + * Returns a contextual shaper for the provided unicode range(s). Latin-1 + * (EUROPEAN) digits will be converted to the decimal digits corresponding to + * the range of the preceding text, if the range is one of the provided ranges. + * Multiple ranges are represented by or-ing the values together, for example, + * {@code NumericShaper.ARABIC | NumericShaper.THAI}. The shaper uses + * defaultContext as the starting context. + * + * @param ranges the specified Unicode ranges + * @param defaultContext the starting context, such as + * {@code NumericShaper.EUROPEAN} + * @return a shaper for the specified Unicode ranges. + * @throws IllegalArgumentException if the specified {@code defaultContext} is + * not a single valid range. + */ + public static NumericShaper getContextualShaper(int ranges, int defaultContext) { + int key = getKeyFromMask(defaultContext); + ranges |= CONTEXTUAL_MASK; + return new NumericShaper(key, ranges); + } + + /** + * Returns a contextual shaper for the provided Unicode range(s). The Latin-1 + * (EUROPEAN) digits will be converted to the decimal digits corresponding to + * the range of the preceding text, if the range is one of the provided ranges. + * The shaper uses {@code + * defaultContext} as the starting context. + * + * @param ranges the specified Unicode ranges + * @param defaultContext the starting context, such as + * {@code NumericShaper.Range.EUROPEAN} + * @return a contextual shaper for the specified Unicode ranges. + * @throws NullPointerException if {@code ranges} or {@code defaultContext} is + * {@code null} + * @since 1.7 + */ + public static NumericShaper getContextualShaper(Set ranges, Range defaultContext) { + if (defaultContext == null) { + throw new NullPointerException(); + } + NumericShaper shaper = new NumericShaper(defaultContext, ranges); + shaper.mask = CONTEXTUAL_MASK; + return shaper; + } + + /** + * Private constructor. + */ + private NumericShaper(int key, int mask) { + this.key = key; + this.mask = mask; + } + + private NumericShaper(Range defaultContext, Set ranges) { + shapingRange = defaultContext; + rangeSet = EnumSet.copyOf(ranges); // throws NPE if ranges is null. + + // Give precedence to EASTERN_ARABIC if both ARABIC and + // EASTERN_ARABIC are specified. + if (rangeSet.contains(Range.EASTERN_ARABIC) && rangeSet.contains(Range.ARABIC)) { + rangeSet.remove(Range.ARABIC); + } + + // As well as the above case, give precedence to TAI_THAM_THAM if both + // TAI_THAM_HORA and TAI_THAM_THAM are specified. + if (rangeSet.contains(Range.TAI_THAM_THAM) && rangeSet.contains(Range.TAI_THAM_HORA)) { + rangeSet.remove(Range.TAI_THAM_HORA); + } + + rangeArray = rangeSet.toArray(new Range[rangeSet.size()]); + if (rangeArray.length > BSEARCH_THRESHOLD) { + // sort rangeArray for binary search + Arrays.sort(rangeArray, new Comparator() { + public int compare(Range s1, Range s2) { + return s1.base > s2.base ? 1 : s1.base == s2.base ? 0 : -1; + } + }); + } + } + + /** + * Converts the digits in the text that occur between start and start + count. + * + * @param text an array of characters to convert + * @param start the index into {@code text} to start converting + * @param count the number of characters in {@code text} to convert + * @throws IndexOutOfBoundsException if start or start + count is out of bounds + * @throws NullPointerException if text is null + */ + public void shape(char[] text, int start, int count) { + checkParams(text, start, count); + if (isContextual()) { + if (rangeSet == null) { + shapeContextually(text, start, count, key); + } else { + shapeContextually(text, start, count, shapingRange); + } + } else { + shapeNonContextually(text, start, count); + } + } + + /** + * Converts the digits in the text that occur between start and start + count, + * using the provided context. Context is ignored if the shaper is not a + * contextual shaper. + * + * @param text an array of characters + * @param start the index into {@code text} to start converting + * @param count the number of characters in {@code text} to convert + * @param context the context to which to convert the characters, such as + * {@code NumericShaper.EUROPEAN} + * @throws IndexOutOfBoundsException if start or start + count is out of bounds + * @throws NullPointerException if text is null + * @throws IllegalArgumentException if this is a contextual shaper and the + * specified {@code context} is not a single + * valid range. + */ + public void shape(char[] text, int start, int count, int context) { + checkParams(text, start, count); + if (isContextual()) { + int ctxKey = getKeyFromMask(context); + if (rangeSet == null) { + shapeContextually(text, start, count, ctxKey); + } else { + shapeContextually(text, start, count, Range.values()[ctxKey]); + } + } else { + shapeNonContextually(text, start, count); + } + } + + /** + * Converts the digits in the text that occur between {@code + * start} and {@code start + count}, using the provided {@code + * context}. {@code Context} is ignored if the shaper is not a contextual + * shaper. + * + * @param text a {@code char} array + * @param start the index into {@code text} to start converting + * @param count the number of {@code char}s in {@code text} to convert + * @param context the context to which to convert the characters, such as + * {@code NumericShaper.Range.EUROPEAN} + * @throws IndexOutOfBoundsException if {@code start} or {@code start + count} + * is out of bounds + * @throws NullPointerException if {@code text} or {@code context} is null + * @since 1.7 + */ + public void shape(char[] text, int start, int count, Range context) { + checkParams(text, start, count); + if (context == null) { + throw new NullPointerException("context is null"); + } + + if (isContextual()) { + if (rangeSet != null) { + shapeContextually(text, start, count, context); + } else { + int key = Range.toRangeIndex(context); + if (key >= 0) { + shapeContextually(text, start, count, key); + } else { + shapeContextually(text, start, count, shapingRange); + } + } + } else { + shapeNonContextually(text, start, count); + } + } + + private void checkParams(char[] text, int start, int count) { + if (text == null) { + throw new NullPointerException("text is null"); + } + if ((start < 0) || (start > text.length) || ((start + count) < 0) || ((start + count) > text.length)) { + throw new IndexOutOfBoundsException("bad start or count for text of length " + text.length); + } + } + + /** + * Returns a {@code boolean} indicating whether or not this shaper shapes + * contextually. + * + * @return {@code true} if this shaper is contextual; {@code false} otherwise. + */ + public boolean isContextual() { + return (mask & CONTEXTUAL_MASK) != 0; + } + + /** + * Returns an {@code int} that ORs together the values for all the ranges that + * will be shaped. + *

+ * For example, to check if a shaper shapes to Arabic, you would use the + * following:

+ * {@code if ((shaper.getRanges() & shaper.ARABIC) != 0) { ... } + *
+ * + *

+ * Note that this method supports only the bit mask-based ranges. Call + * {@link #getRangeSet()} for the enum-based ranges. + * + * @return the values for all the ranges to be shaped. + */ + public int getRanges() { + return mask & ~CONTEXTUAL_MASK; + } + + /** + * Returns a {@code Set} representing all the Unicode ranges in this + * {@code NumericShaper} that will be shaped. + * + * @return all the Unicode ranges to be shaped. + * @since 1.7 + */ + public Set getRangeSet() { + if (rangeSet != null) { + return EnumSet.copyOf(rangeSet); + } + return Range.maskToRangeSet(mask); + } + + /** + * Perform non-contextual shaping. + */ + private void shapeNonContextually(char[] text, int start, int count) { + int base; + char minDigit = '0'; + if (shapingRange != null) { + base = shapingRange.getDigitBase(); + minDigit += shapingRange.getNumericBase(); + } else { + base = bases[key]; + if (key == ETHIOPIC_KEY) { + minDigit++; // Ethiopic doesn't use decimal zero + } + } + for (int i = start, e = start + count; i < e; ++i) { + char c = text[i]; + if (c >= minDigit && c <= '\u0039') { + text[i] = (char) (c + base); + } + } + } + + /** + * Perform contextual shaping. Synchronized to protect caches used in + * getContextKey. + */ + private synchronized void shapeContextually(char[] text, int start, int count, int ctxKey) { + + // if we don't support this context, then don't shape + if ((mask & (1 << ctxKey)) == 0) { + ctxKey = EUROPEAN_KEY; + } + int lastkey = ctxKey; + + int base = bases[ctxKey]; + char minDigit = ctxKey == ETHIOPIC_KEY ? '1' : '0'; // Ethiopic doesn't use decimal zero + + synchronized (NumericShaper.class) { + for (int i = start, e = start + count; i < e; ++i) { + char c = text[i]; + if (c >= minDigit && c <= '\u0039') { + text[i] = (char) (c + base); + } + + if (isStrongDirectional(c)) { + int newkey = getContextKey(c); + if (newkey != lastkey) { + lastkey = newkey; + + ctxKey = newkey; + if (((mask & EASTERN_ARABIC) != 0) && (ctxKey == ARABIC_KEY || ctxKey == EASTERN_ARABIC_KEY)) { + ctxKey = EASTERN_ARABIC_KEY; + } else if (((mask & ARABIC) != 0) && (ctxKey == ARABIC_KEY || ctxKey == EASTERN_ARABIC_KEY)) { + ctxKey = ARABIC_KEY; + } else if ((mask & (1 << ctxKey)) == 0) { + ctxKey = EUROPEAN_KEY; + } + + base = bases[ctxKey]; + + minDigit = ctxKey == ETHIOPIC_KEY ? '1' : '0'; // Ethiopic doesn't use decimal zero + } + } + } + } + } + + private void shapeContextually(char[] text, int start, int count, Range ctxKey) { + // if we don't support the specified context, then don't shape. + if (ctxKey == null || !rangeSet.contains(ctxKey)) { + ctxKey = Range.EUROPEAN; + } + + Range lastKey = ctxKey; + int base = ctxKey.getDigitBase(); + char minDigit = (char) ('0' + ctxKey.getNumericBase()); + final int end = start + count; + for (int i = start; i < end; ++i) { + char c = text[i]; + if (c >= minDigit && c <= '9') { + text[i] = (char) (c + base); + continue; + } + if (isStrongDirectional(c)) { + ctxKey = rangeForCodePoint(c); + if (ctxKey != lastKey) { + lastKey = ctxKey; + base = ctxKey.getDigitBase(); + minDigit = (char) ('0' + ctxKey.getNumericBase()); + } + } + } + } + + /** + * Returns a hash code for this shaper. + * + * @return this shaper's hash code. + * @see java.lang.Object#hashCode + */ + public int hashCode() { + int hash = mask; + if (rangeSet != null) { + // Use the CONTEXTUAL_MASK bit only for the enum-based + // NumericShaper. A deserialized NumericShaper might have + // bit masks. + hash &= CONTEXTUAL_MASK; + hash ^= rangeSet.hashCode(); + } + return hash; + } + + /** + * Returns {@code true} if the specified object is an instance of + * {@code NumericShaper} and shapes identically to this one, regardless of the + * range representations, the bit mask or the enum. For example, the following + * code produces {@code "true"}.

+ * + *
+	 * NumericShaper ns1 = NumericShaper.getShaper(NumericShaper.ARABIC);
+	 * NumericShaper ns2 = NumericShaper.getShaper(NumericShaper.Range.ARABIC);
+	 * System.out.println(ns1.equals(ns2));
+	 * 
+ * + *
+ * + * @param o the specified object to compare to this {@code NumericShaper} + * @return {@code true} if {@code o} is an instance of {@code NumericShaper} and + * shapes in the same way; {@code false} otherwise. + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object o) { + if (o != null) { + try { + NumericShaper rhs = (NumericShaper) o; + if (rangeSet != null) { + if (rhs.rangeSet != null) { + return isContextual() == rhs.isContextual() && rangeSet.equals(rhs.rangeSet) + && shapingRange == rhs.shapingRange; + } + return isContextual() == rhs.isContextual() && rangeSet.equals(Range.maskToRangeSet(rhs.mask)) + && shapingRange == Range.indexToRange(rhs.key); + } else if (rhs.rangeSet != null) { + Set rset = Range.maskToRangeSet(mask); + Range srange = Range.indexToRange(key); + return isContextual() == rhs.isContextual() && rset.equals(rhs.rangeSet) + && srange == rhs.shapingRange; + } + return rhs.mask == mask && rhs.key == key; + } catch (ClassCastException e) { + } + } + return false; + } + + /** + * Returns a {@code String} that describes this shaper. This method is used for + * debugging purposes only. + * + * @return a {@code String} describing this shaper. + */ + public String toString() { + StringBuilder buf = new StringBuilder(super.toString()); + + buf.append("[contextual:").append(isContextual()); + + String[] keyNames = null; + if (isContextual()) { + buf.append(", context:"); + buf.append(shapingRange == null ? Range.values()[key] : shapingRange); + } + + if (rangeSet == null) { + buf.append(", range(s): "); + boolean first = true; + for (int i = 0; i < NUM_KEYS; ++i) { + if ((mask & (1 << i)) != 0) { + if (first) { + first = false; + } else { + buf.append(", "); + } + buf.append(Range.values()[i]); + } + } + } else { + buf.append(", range set: ").append(rangeSet); + } + buf.append(']'); + + return buf.toString(); + } + + /** + * Returns the index of the high bit in value (assuming le, actually power of 2 + * >= value). value must be positive. + */ + private static int getHighBit(int value) { + if (value <= 0) { + return -32; + } + + int bit = 0; + + if (value >= 1 << 16) { + value >>= 16; + bit += 16; + } + + if (value >= 1 << 8) { + value >>= 8; + bit += 8; + } + + if (value >= 1 << 4) { + value >>= 4; + bit += 4; + } + + if (value >= 1 << 2) { + value >>= 2; + bit += 2; + } + + if (value >= 1 << 1) { + bit += 1; + } + + return bit; + } + + /** + * fast binary search over subrange of array. + */ + private static int search(int value, int[] array, int start, int length) { + int power = 1 << getHighBit(length); + int extra = length - power; + int probe = power; + int index = start; + + if (value >= array[index + extra]) { + index += extra; + } + + while (probe > 1) { + probe >>= 1; + + if (value >= array[index + probe]) { + index += probe; + } + } + + return index; + } + + /** + * Converts the {@code NumericShaper.Range} enum-based parameters, if any, to + * the bit mask-based counterparts and writes this object to the {@code stream}. + * Any enum constants that have no bit mask-based counterparts are ignored in + * the conversion. + * + * @param stream the output stream to write to + * @throws IOException if an I/O error occurs while writing to {@code stream} + * @since 1.7 + */ + private void writeObject(ObjectOutputStream stream) throws IOException { + if (shapingRange != null) { + int index = Range.toRangeIndex(shapingRange); + if (index >= 0) { + key = index; + } + } + if (rangeSet != null) { + mask |= Range.toRangeMask(rangeSet); + } + stream.defaultWriteObject(); + } +} diff --git a/src/main/java/jdk_internal/bidi/ParseException.java b/src/main/java/jdk_internal/bidi/ParseException.java new file mode 100755 index 00000000..3d3e9d09 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/ParseException.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved + * + * The original version of this source code and documentation is copyrighted + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These + * materials are provided under terms of a License Agreement between Taligent + * and Sun. This technology is protected by multiple US and International + * patents. This notice and attribution to Taligent may not be removed. + * Taligent is a registered trademark of Taligent, Inc. + * + */ + +package jdk_internal.bidi; + +/** + * Signals that an error has been reached unexpectedly while parsing. + * + * @see java.lang.Exception + * @see java.text.Format + * @see java.text.FieldPosition + * @author Mark Davis + * @since 1.1 + */ +public class ParseException extends Exception { + + private static final long serialVersionUID = 2703218443322787634L; + + /** + * Constructs a ParseException with the specified detail message and offset. A + * detail message is a String that describes this particular exception. + * + * @param s the detail message + * @param errorOffset the position where the error is found while parsing. + */ + public ParseException(String s, int errorOffset) { + super(s); + this.errorOffset = errorOffset; + } + + /** + * Returns the position where the error was found. + * + * @return the position where the error was found + */ + public int getErrorOffset() { + return errorOffset; + } + + // ============ privates ============ + /** + * The zero-based character offset into the string being parsed at which the + * error was found during parsing. + * + * @serial + */ + private int errorOffset; +} diff --git a/src/main/java/jdk_internal/bidi/SunNormalizer.java b/src/main/java/jdk_internal/bidi/SunNormalizer.java new file mode 100755 index 00000000..d1f57bca --- /dev/null +++ b/src/main/java/jdk_internal/bidi/SunNormalizer.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk_internal.bidi; + +import jdk_internal.bidi.icu.lang.UCharacter; +import jdk_internal.bidi.icu.text.NormalizerBase; + +/** + * This Normalizer is for Unicode 3.2 support for IDNA only. Developers should + * not use this class. + * + * @since 1.6 + */ +public final class SunNormalizer { + + private SunNormalizer() { + }; + + /** + * Option to select Unicode 3.2 (without corrigendum 4 corrections) for + * normalization. + */ + public static final int UNICODE_3_2 = NormalizerBase.UNICODE_3_2_0_ORIGINAL; + + /** + * Normalize a sequence of char values. The sequence will be normalized + * according to the specified normalization from. + * + * @param src The sequence of char values to normalize. + * @param form The normalization form; one of + * {@link java.text.Normalizer.Form#NFC}, + * {@link java.text.Normalizer.Form#NFD}, + * {@link java.text.Normalizer.Form#NFKC}, + * {@link java.text.Normalizer.Form#NFKD} + * @param option The normalization option; + * {@link sun.text.Normalizer#UNICODE_3_2} + * @return The normalized String + * @throws NullPointerException If src or form is + * null. + */ + public static String normalize(CharSequence src, Normalizer.Form form, int option) { + return NormalizerBase.normalize(src.toString(), form, option); + }; + + /** + * Determines if the given sequence of char values is normalized. + * + * @param src The sequence of char values to be checked. + * @param form The normalization form; one of + * {@link java.text.Normalizer.Form#NFC}, + * {@link java.text.Normalizer.Form#NFD}, + * {@link java.text.Normalizer.Form#NFKC}, + * {@link java.text.Normalizer.Form#NFKD} + * @param option The normalization option; + * {@link sun.text.Normalizer#UNICODE_3_2} + * @return true if the sequence of char values is normalized; false otherwise. + * @throws NullPointerException If src or form is + * null. + */ + public static boolean isNormalized(CharSequence src, Normalizer.Form form, int option) { + return NormalizerBase.isNormalized(src.toString(), form, option); + } + + /** + * Returns the combining class of the given character + * + * @param ch character to retrieve combining class of + * @return combining class of the given character + */ + public static final int getCombiningClass(int ch) { + return UCharacter.getCombiningClass(ch); + } +} diff --git a/src/main/java/jdk_internal/bidi/TextAttribute.java b/src/main/java/jdk_internal/bidi/TextAttribute.java new file mode 100755 index 00000000..003e85b7 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/TextAttribute.java @@ -0,0 +1,1065 @@ +/* + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved + * (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved + * + * The original version of this source code and documentation is + * copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary + * of IBM. These materials are provided under terms of a License + * Agreement between Taligent and Sun. This technology is protected + * by multiple US and International patents. + * + * This notice and attribution to Taligent may not be removed. + * Taligent is a registered trademark of Taligent, Inc. + * + */ + +package jdk_internal.bidi; + +import java.io.InvalidObjectException; +import java.util.HashMap; +import java.util.Map; + +import jdk_internal.bidi.AttributedCharacterIterator.Attribute; + +/** + * The {@code TextAttribute} class defines attribute keys and attribute values + * used for text rendering. + *

+ * {@code TextAttribute} instances are used as attribute keys to identify + * attributes in {@link java.awt.Font Font}, {@link java.awt.font.TextLayout + * TextLayout}, {@link java.text.AttributedCharacterIterator + * AttributedCharacterIterator}, and other classes handling text attributes. + * Other constants defined in this class can be used as attribute values. + *

+ * For each text attribute, the documentation provides: + *

    + *
  • the type of its value, + *
  • the relevant predefined constants, if any + *
  • the default effect if the attribute is absent + *
  • the valid values if there are limitations + *
  • a description of the effect. + *
+ * + *

Values

+ *
    + *
  • The values of attributes must always be immutable. + *
  • Where value limitations are given, any value outside of that set is + * reserved for future use; the value will be treated as the default. + *
  • The value {@code null} is treated the same as the default value and + * results in the default behavior. + *
  • If the value is not of the proper type, the attribute will be ignored. + *
  • The identity of the value does not matter, only the actual value. For + * example, {@code TextAttribute.WEIGHT_BOLD} and {@code Float.valueOf(2.0f)} + * indicate the same {@code WEIGHT}. + *
  • Attribute values of type {@code Number} (used for {@code WEIGHT}, + * {@code WIDTH}, {@code POSTURE}, {@code SIZE}, {@code JUSTIFICATION}, and + * {@code TRACKING}) can vary along their natural range and are not restricted + * to the predefined constants. {@code Number.floatValue()} is used to get the + * actual value from the {@code Number}. + *
  • The values for {@code WEIGHT}, {@code WIDTH}, and {@code POSTURE} are + * interpolated by the system, which can select the 'nearest available' font or + * use other techniques to approximate the user's request. + * + *
+ * + *

Summary of attributes

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Key, value type, principal constants, and default value behavior of + * all TextAttributes
Key + * Value Type + * Principal Constants + * Default Value
{@link #FAMILY} + * String + * See Font {@link java.awt.Font#DIALOG DIALOG}, + * {@link java.awt.Font#DIALOG_INPUT DIALOG_INPUT},
+ * {@link java.awt.Font#SERIF SERIF}, {@link java.awt.Font#SANS_SERIF + * SANS_SERIF}, and {@link java.awt.Font#MONOSPACED MONOSPACED}. + *
"Default" (use platform default) + *
{@link #WEIGHT} + * Number + * WEIGHT_REGULAR, WEIGHT_BOLD + * WEIGHT_REGULAR + *
{@link #WIDTH} + * Number + * WIDTH_CONDENSED, WIDTH_REGULAR,
+ * WIDTH_EXTENDED + *
WIDTH_REGULAR + *
{@link #POSTURE} + * Number + * POSTURE_REGULAR, POSTURE_OBLIQUE + * POSTURE_REGULAR + *
{@link #SIZE} + * Number + * none + * 12.0 + *
{@link #TRANSFORM} + * {@link TransformAttribute} + * See TransformAttribute {@link TransformAttribute#IDENTITY IDENTITY} + * TransformAttribute.IDENTITY + *
{@link #SUPERSCRIPT} + * Integer + * SUPERSCRIPT_SUPER, SUPERSCRIPT_SUB + * 0 (use the standard glyphs and metrics) + *
{@link #FONT} + * {@link java.awt.Font} + * none + * null (do not override font resolution) + *
{@link #CHAR_REPLACEMENT} + * {@link GraphicAttribute} + * none + * null (draw text using font glyphs) + *
{@link #FOREGROUND} + * {@link java.awt.Paint} + * none + * null (use current graphics paint) + *
{@link #BACKGROUND} + * {@link java.awt.Paint} + * none + * null (do not render background) + *
{@link #UNDERLINE} + * Integer + * UNDERLINE_ON + * -1 (do not render underline) + *
{@link #STRIKETHROUGH} + * Boolean + * STRIKETHROUGH_ON + * false (do not render strikethrough) + *
{@link #RUN_DIRECTION} + * Boolean + * RUN_DIRECTION_LTR
+ * RUN_DIRECTION_RTL + *
null (use {@link java.text.Bidi} standard default) + *
{@link #BIDI_EMBEDDING} + * Integer + * none + * 0 (use base line direction) + *
{@link #JUSTIFICATION} + * Number + * JUSTIFICATION_FULL + * JUSTIFICATION_FULL + *
{@link #INPUT_METHOD_HIGHLIGHT} + * {@link java.awt.im.InputMethodHighlight},
+ * {@link java.text.Annotation} + *
(see class) + * null (do not apply input highlighting) + *
{@link #INPUT_METHOD_UNDERLINE} + * Integer + * UNDERLINE_LOW_ONE_PIXEL,
+ * UNDERLINE_LOW_TWO_PIXEL + *
-1 (do not render underline) + *
{@link #SWAP_COLORS} + * Boolean + * SWAP_COLORS_ON + * false (do not swap colors) + *
{@link #NUMERIC_SHAPING} + * {@link java.awt.font.NumericShaper} + * none + * null (do not shape digits) + *
{@link #KERNING} + * Integer + * KERNING_ON + * 0 (do not request kerning) + *
{@link #LIGATURES} + * Integer + * LIGATURES_ON + * 0 (do not form optional ligatures) + *
{@link #TRACKING} + * Number + * TRACKING_LOOSE, TRACKING_TIGHT + * 0 (do not add tracking) + *
+ * + * @see java.awt.Font + * @see java.awt.font.TextLayout + * @see java.text.AttributedCharacterIterator + */ +public final class TextAttribute extends Attribute { + + // table of all instances in this class, used by readResolve + private static final Map instanceMap = new HashMap(29); + + /** + * Constructs a {@code TextAttribute} with the specified name. + * + * @param name the attribute name to assign to this {@code TextAttribute} + */ + protected TextAttribute(String name) { + super(name); + if (this.getClass() == TextAttribute.class) { + instanceMap.put(name, this); + } + } + + /** + * Resolves instances being deserialized to the predefined constants. + */ + protected Object readResolve() throws InvalidObjectException { + if (this.getClass() != TextAttribute.class) { + throw new InvalidObjectException("subclass didn't correctly implement readResolve"); + } + + TextAttribute instance = instanceMap.get(getName()); + if (instance != null) { + return instance; + } else { + throw new InvalidObjectException("unknown attribute name"); + } + } + + /** + * Use serialVersionUID from JDK 1.2 for interoperability. 1.2 will throw an + * InvalidObjectException if ever asked to deserialize INPUT_METHOD_UNDERLINE. + * This shouldn't happen in real life. + */ + private static final long serialVersionUID = 7744112784117861702L; + + // + // For use with Font. + // + + /** + * Attribute key for the font name. Values are instances of + * {@code String}. The default value is {@code "Default"}, which causes + * the platform default font family to be used. + * + *

+ * The {@code Font} class defines constants for the logical font names + * {@link java.awt.Font#DIALOG DIALOG}, {@link java.awt.Font#DIALOG_INPUT + * DIALOG_INPUT}, {@link java.awt.Font#SANS_SERIF SANS_SERIF}, + * {@link java.awt.Font#SERIF SERIF}, and {@link java.awt.Font#MONOSPACED + * MONOSPACED}. + * + *

+ * This defines the value passed as {@code name} to the {@code Font} + * constructor. Both logical and physical font names are allowed. If a font with + * the requested name is not found, the default font is used. + * + *

+ * Note: This attribute is unfortunately misnamed, as it specifies the + * face name and not just the family. Thus values such as "Lucida Sans Bold" + * will select that face if it exists. Note, though, that if the requested face + * does not exist, the default will be used with regular weight. The + * "Bold" in the name is part of the face name, not a separate request that the + * font's weight be bold. + *

+ */ + public static final TextAttribute FAMILY = new TextAttribute("family"); + + /** + * Attribute key for the weight of a font. Values are instances of + * {@code Number}. The default value is {@code WEIGHT_REGULAR}. + * + *

+ * Several constant values are provided, see {@link #WEIGHT_EXTRA_LIGHT}, + * {@link #WEIGHT_LIGHT}, {@link #WEIGHT_DEMILIGHT}, {@link #WEIGHT_REGULAR}, + * {@link #WEIGHT_SEMIBOLD}, {@link #WEIGHT_MEDIUM}, {@link #WEIGHT_DEMIBOLD}, + * {@link #WEIGHT_BOLD}, {@link #WEIGHT_HEAVY}, {@link #WEIGHT_EXTRABOLD}, and + * {@link #WEIGHT_ULTRABOLD}. The value {@code WEIGHT_BOLD} corresponds to the + * style value {@code Font.BOLD} as passed to the {@code Font} constructor. + * + *

+ * The value is roughly the ratio of the stem width to that of the regular + * weight. + * + *

+ * The system can interpolate the provided value. + */ + public static final TextAttribute WEIGHT = new TextAttribute("weight"); + + /** + * The lightest predefined weight. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_EXTRA_LIGHT = Float.valueOf(0.5f); + + /** + * The standard light weight. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_LIGHT = Float.valueOf(0.75f); + + /** + * An intermediate weight between {@code WEIGHT_LIGHT} and + * {@code WEIGHT_STANDARD}. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_DEMILIGHT = Float.valueOf(0.875f); + + /** + * The standard weight. This is the default value for {@code WEIGHT}. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_REGULAR = Float.valueOf(1.0f); + + /** + * A moderately heavier weight than {@code WEIGHT_REGULAR}. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_SEMIBOLD = Float.valueOf(1.25f); + + /** + * An intermediate weight between {@code WEIGHT_REGULAR} and + * {@code WEIGHT_BOLD}. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_MEDIUM = Float.valueOf(1.5f); + + /** + * A moderately lighter weight than {@code WEIGHT_BOLD}. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_DEMIBOLD = Float.valueOf(1.75f); + + /** + * The standard bold weight. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_BOLD = Float.valueOf(2.0f); + + /** + * A moderately heavier weight than {@code WEIGHT_BOLD}. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_HEAVY = Float.valueOf(2.25f); + + /** + * An extra heavy weight. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_EXTRABOLD = Float.valueOf(2.5f); + + /** + * The heaviest predefined weight. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_ULTRABOLD = Float.valueOf(2.75f); + + /** + * Attribute key for the width of a font. Values are instances of + * {@code Number}. The default value is {@code WIDTH_REGULAR}. + * + *

+ * Several constant values are provided, see {@link #WIDTH_CONDENSED}, + * {@link #WIDTH_SEMI_CONDENSED}, {@link #WIDTH_REGULAR}, + * {@link #WIDTH_SEMI_EXTENDED}, {@link #WIDTH_EXTENDED}. + * + *

+ * The value is roughly the ratio of the advance width to that of the regular + * width. + * + *

+ * The system can interpolate the provided value. + */ + public static final TextAttribute WIDTH = new TextAttribute("width"); + + /** + * The most condensed predefined width. + * + * @see #WIDTH + */ + public static final Float WIDTH_CONDENSED = Float.valueOf(0.75f); + + /** + * A moderately condensed width. + * + * @see #WIDTH + */ + public static final Float WIDTH_SEMI_CONDENSED = Float.valueOf(0.875f); + + /** + * The standard width. This is the default value for {@code WIDTH}. + * + * @see #WIDTH + */ + public static final Float WIDTH_REGULAR = Float.valueOf(1.0f); + + /** + * A moderately extended width. + * + * @see #WIDTH + */ + public static final Float WIDTH_SEMI_EXTENDED = Float.valueOf(1.25f); + + /** + * The most extended predefined width. + * + * @see #WIDTH + */ + public static final Float WIDTH_EXTENDED = Float.valueOf(1.5f); + + /** + * Attribute key for the posture of a font. Values are instances of + * {@code Number}. The default value is {@code POSTURE_REGULAR}. + * + *

+ * Two constant values are provided, {@link #POSTURE_REGULAR} and + * {@link #POSTURE_OBLIQUE}. The value {@code POSTURE_OBLIQUE} corresponds to + * the style value {@code Font.ITALIC} as passed to the {@code Font} + * constructor. + * + *

+ * The value is roughly the slope of the stems of the font, expressed as the run + * over the rise. Positive values lean right. + * + *

+ * The system can interpolate the provided value. + * + *

+ * This will affect the font's italic angle as returned by + * {@code Font.getItalicAngle}. + * + * @see java.awt.Font#getItalicAngle() + */ + public static final TextAttribute POSTURE = new TextAttribute("posture"); + + /** + * The standard posture, upright. This is the default value for {@code POSTURE}. + * + * @see #POSTURE + */ + public static final Float POSTURE_REGULAR = Float.valueOf(0.0f); + + /** + * The standard italic posture. + * + * @see #POSTURE + */ + public static final Float POSTURE_OBLIQUE = Float.valueOf(0.20f); + + /** + * Attribute key for the font size. Values are instances of + * {@code Number}. The default value is 12pt. + * + *

+ * This corresponds to the {@code size} parameter to the {@code Font} + * constructor. + * + *

+ * Very large or small sizes will impact rendering performance, and the + * rendering system might not render text at these sizes. Negative sizes are + * illegal and result in the default size. + * + *

+ * Note that the appearance and metrics of a 12pt font with a 2x transform might + * be different than that of a 24 point font with no transform. + */ + public static final TextAttribute SIZE = new TextAttribute("size"); + + /** + * Attribute key for the transform of a font. Values are instances of + * {@code TransformAttribute}. The default value is + * {@code TransformAttribute.IDENTITY}. + * + *

+ * The {@code TransformAttribute} class defines the constant + * {@link TransformAttribute#IDENTITY IDENTITY}. + * + *

+ * This corresponds to the transform passed to + * {@code Font.deriveFont(AffineTransform)}. Since that transform is mutable and + * {@code TextAttribute} values must not be, the {@code TransformAttribute} + * wrapper class is used. + * + *

+ * The primary intent is to support scaling and skewing, though other effects + * are possible. + *

+ * + *

+ * Some transforms will cause the baseline to be rotated and/or shifted. The + * text and the baseline are transformed together so that the text follows the + * new baseline. For example, with text on a horizontal baseline, the new + * baseline follows the direction of the unit x vector passed through the + * transform. Text metrics are measured against this new baseline. So, for + * example, with other things being equal, text rendered with a rotated + * TRANSFORM and an unrotated TRANSFORM will measure as having the same ascent, + * descent, and advance. + *

+ * + *

+ * In styled text, the baselines for each such run are aligned one after the + * other to potentially create a non-linear baseline for the entire run of text. + * For more information, see {@link TextLayout#getLayoutPath}. + *

+ * + * @see TransformAttribute + * @see java.awt.geom.AffineTransform + */ + public static final TextAttribute TRANSFORM = new TextAttribute("transform"); + + /** + * Attribute key for superscripting and subscripting. Values are instances of + * {@code Integer}. The default value is 0, which means that no + * superscript or subscript is used. + * + *

+ * Two constant values are provided, see {@link #SUPERSCRIPT_SUPER} and + * {@link #SUPERSCRIPT_SUB}. These have the values 1 and -1 respectively. Values + * of greater magnitude define greater levels of superscript or subscripting, + * for example, 2 corresponds to super-superscript, 3 to + * super-super-superscript, and similarly for negative values and subscript, up + * to a level of 7 (or -7). Values beyond this range are reserved; behavior is + * platform-dependent. + * + *

+ * {@code SUPERSCRIPT} can impact the ascent and descent of a font. The ascent + * and descent can never become negative, however. + */ + public static final TextAttribute SUPERSCRIPT = new TextAttribute("superscript"); + + /** + * Standard superscript. + * + * @see #SUPERSCRIPT + */ + public static final Integer SUPERSCRIPT_SUPER = Integer.valueOf(1); + + /** + * Standard subscript. + * + * @see #SUPERSCRIPT + */ + public static final Integer SUPERSCRIPT_SUB = Integer.valueOf(-1); + + /** + * Attribute key used to provide the font to use to render text. Values are + * instances of {@link java.awt.Font}. The default value is null, indicating + * that normal resolution of a {@code Font} from attributes should be performed. + * + *

+ * {@code TextLayout} and {@code AttributedCharacterIterator} work in terms of + * {@code Maps} of {@code TextAttributes}. Normally, all the attributes are + * examined and used to select and configure a {@code Font} instance. If a + * {@code FONT} attribute is present, though, its associated {@code Font} will + * be used. This provides a way for users to override the resolution of font + * attributes into a {@code Font}, or force use of a particular {@code Font} + * instance. This also allows users to specify subclasses of {@code Font} in + * cases where a {@code Font} can be subclassed. + * + *

+ * {@code FONT} is used for special situations where clients already have a + * {@code Font} instance but still need to use {@code Map}-based APIs. + * Typically, there will be no other attributes in the {@code Map} except the + * {@code FONT} attribute. With {@code Map}-based APIs the common case is to + * specify all attributes individually, so {@code FONT} is not needed or + * desirable. + * + *

+ * However, if both {@code FONT} and other attributes are present in the + * {@code Map}, the rendering system will merge the attributes defined in the + * {@code Font} with the additional attributes. This merging process classifies + * {@code TextAttributes} into two groups. One group, the 'primary' group, is + * considered fundamental to the selection and metric behavior of a font. These + * attributes are {@code FAMILY}, {@code WEIGHT}, {@code WIDTH}, + * {@code POSTURE}, {@code SIZE}, {@code TRANSFORM}, {@code SUPERSCRIPT}, and + * {@code TRACKING}. The other group, the 'secondary' group, consists of all + * other defined attributes, with the exception of {@code FONT} itself. + * + *

+ * To generate the new {@code Map}, first the {@code Font} is obtained from the + * {@code FONT} attribute, and all of its attributes extracted into a + * new {@code Map}. Then only the secondary attributes from the + * original {@code Map} are added to those in the new {@code Map}. Thus the + * values of primary attributes come solely from the {@code Font}, and the + * values of secondary attributes originate with the {@code Font} but can be + * overridden by other values in the {@code Map}. + * + *

+ * Note:{@code Font's Map}-based constructor and {@code deriveFont} + * methods do not process the {@code FONT} attribute, as these are used to + * create new {@code Font} objects. Instead, {@link java.awt.Font#getFont(Map) + * Font.getFont(Map)} should be used to handle the {@code FONT} attribute. + * + * @see java.awt.Font + */ + public static final TextAttribute FONT = new TextAttribute("font"); + + /** + * Attribute key for a user-defined glyph to display in lieu of the font's + * standard glyph for a character. Values are instances of GraphicAttribute. The + * default value is null, indicating that the standard glyphs provided by the + * font should be used. + * + *

+ * This attribute is used to reserve space for a graphic or other component + * embedded in a line of text. It is required for correct positioning of + * 'inline' components within a line when bidirectional reordering (see + * {@link java.text.Bidi}) is performed. Each character (Unicode code point) + * will be rendered using the provided GraphicAttribute. Typically, the + * characters to which this attribute is applied should be + * \uFFFC. + * + *

+ * The GraphicAttribute determines the logical and visual bounds of the text; + * the actual Font values are ignored. + * + * @see GraphicAttribute + */ + public static final TextAttribute CHAR_REPLACEMENT = new TextAttribute("char_replacement"); + + // + // Adornments added to text. + // + + /** + * Attribute key for the paint used to render the text. Values are instances of + * {@code Paint}. The default value is null, indicating that the + * {@code Paint} set on the {@code Graphics2D} at the time of rendering is used. + * + *

+ * Glyphs will be rendered using this {@code Paint} regardless of the + * {@code Paint} value set on the {@code Graphics} (but see + * {@link #SWAP_COLORS}). + * + * @see java.awt.Paint + * @see #SWAP_COLORS + */ + public static final TextAttribute FOREGROUND = new TextAttribute("foreground"); + + /** + * Attribute key for the paint used to render the background of the text. Values + * are instances of {@code Paint}. The default value is null, indicating + * that the background should not be rendered. + * + *

+ * The logical bounds of the text will be filled using this {@code Paint}, and + * then the text will be rendered on top of it (but see {@link #SWAP_COLORS}). + * + *

+ * The visual bounds of the text is extended to include the logical bounds, if + * necessary. The outline is not affected. + * + * @see java.awt.Paint + * @see #SWAP_COLORS + */ + public static final TextAttribute BACKGROUND = new TextAttribute("background"); + + /** + * Attribute key for underline. Values are instances of {@code Integer}. + * The default value is -1, which means no underline. + * + *

+ * The constant value {@link #UNDERLINE_ON} is provided. + * + *

+ * The underline affects both the visual bounds and the outline of the text. + */ + public static final TextAttribute UNDERLINE = new TextAttribute("underline"); + + /** + * Standard underline. + * + * @see #UNDERLINE + */ + public static final Integer UNDERLINE_ON = Integer.valueOf(0); + + /** + * Attribute key for strikethrough. Values are instances of + * {@code Boolean}. The default value is {@code false}, which means no + * strikethrough. + * + *

+ * The constant value {@link #STRIKETHROUGH_ON} is provided. + * + *

+ * The strikethrough affects both the visual bounds and the outline of the text. + */ + public static final TextAttribute STRIKETHROUGH = new TextAttribute("strikethrough"); + + /** + * A single strikethrough. + * + * @see #STRIKETHROUGH + */ + public static final Boolean STRIKETHROUGH_ON = Boolean.TRUE; + + // + // Attributes use to control layout of text on a line. + // + + /** + * Attribute key for the run direction of the line. Values are instances of + * {@code Boolean}. The default value is null, which indicates that the + * standard Bidi algorithm for determining run direction should be used with the + * value {@link java.text.Bidi#DIRECTION_DEFAULT_LEFT_TO_RIGHT}. + * + *

+ * The constants {@link #RUN_DIRECTION_RTL} and {@link #RUN_DIRECTION_LTR} are + * provided. + * + *

+ * This determines the value passed to the {@link java.text.Bidi} constructor to + * select the primary direction of the text in the paragraph. + * + *

+ * Note: This attribute should have the same value for all the text in + * a paragraph, otherwise the behavior is undetermined. + * + * @see java.text.Bidi + */ + public static final TextAttribute RUN_DIRECTION = new TextAttribute("run_direction"); + + /** + * Left-to-right run direction. + * + * @see #RUN_DIRECTION + */ + public static final Boolean RUN_DIRECTION_LTR = Boolean.FALSE; + + /** + * Right-to-left run direction. + * + * @see #RUN_DIRECTION + */ + public static final Boolean RUN_DIRECTION_RTL = Boolean.TRUE; + + /** + * Attribute key for the embedding level of the text. Values are instances of + * {@code Integer}. The default value is {@code null}, indicating that + * the Bidirectional algorithm should run without explicit embeddings. + * + *

+ * Positive values 1 through 61 are embedding levels, negative values + * -1 through -61 are override levels. The value 0 means that the base + * line direction is used. These levels are passed in the embedding levels array + * to the {@link java.text.Bidi} constructor. + * + *

+ * Note: When this attribute is present anywhere in a paragraph, then + * any Unicode bidi control characters (RLO, LRO, RLE, LRE, and PDF) in the + * paragraph are disregarded, and runs of text where this attribute is not + * present are treated as though it were present and had the value 0. + * + * @see java.text.Bidi + */ + public static final TextAttribute BIDI_EMBEDDING = new TextAttribute("bidi_embedding"); + + /** + * Attribute key for the justification of a paragraph. Values are instances of + * {@code Number}. The default value is 1, indicating that justification + * should use the full width provided. Values are pinned to the range [0..1]. + * + *

+ * The constants {@link #JUSTIFICATION_FULL} and {@link #JUSTIFICATION_NONE} are + * provided. + * + *

+ * Specifies the fraction of the extra space to use when justification is + * requested on a {@code TextLayout}. For example, if the line is 50 points wide + * and it is requested to justify to 70 points, a value of 0.75 will pad to use + * three-quarters of the remaining space, or 15 points, so that the resulting + * line will be 65 points in length. + * + *

+ * Note: This should have the same value for all the text in a + * paragraph, otherwise the behavior is undetermined. + * + * @see TextLayout#getJustifiedLayout + */ + public static final TextAttribute JUSTIFICATION = new TextAttribute("justification"); + + /** + * Justify the line to the full requested width. This is the default value for + * {@code JUSTIFICATION}. + * + * @see #JUSTIFICATION + */ + public static final Float JUSTIFICATION_FULL = Float.valueOf(1.0f); + + /** + * Do not allow the line to be justified. + * + * @see #JUSTIFICATION + */ + public static final Float JUSTIFICATION_NONE = Float.valueOf(0.0f); + + // + // For use by input method. + // + + /** + * Attribute key for input method highlight styles. + * + *

+ * Values are instances of {@link java.awt.im.InputMethodHighlight} or + * {@link java.text.Annotation}. The default value is {@code null}, which means + * that input method styles should not be applied before rendering. + * + *

+ * If adjacent runs of text with the same {@code InputMethodHighlight} need to + * be rendered separately, the {@code InputMethodHighlights} should be wrapped + * in {@code Annotation} instances. + * + *

+ * Input method highlights are used while text is being composed by an input + * method. Text editing components should retain them even if they generally + * only deal with unstyled text, and make them available to the drawing + * routines. + * + * @see java.awt.Font + * @see java.awt.im.InputMethodHighlight + * @see java.text.Annotation + */ + public static final TextAttribute INPUT_METHOD_HIGHLIGHT = new TextAttribute("input method highlight"); + + /** + * Attribute key for input method underlines. Values are instances of + * {@code Integer}. The default value is {@code -1}, which means no + * underline. + * + *

+ * Several constant values are provided, see {@link #UNDERLINE_LOW_ONE_PIXEL}, + * {@link #UNDERLINE_LOW_TWO_PIXEL}, {@link #UNDERLINE_LOW_DOTTED}, + * {@link #UNDERLINE_LOW_GRAY}, and {@link #UNDERLINE_LOW_DASHED}. + * + *

+ * This may be used in conjunction with {@link #UNDERLINE} if desired. The + * primary purpose is for use by input methods. Other use of these underlines + * for simple ornamentation might confuse users. + * + *

+ * The input method underline affects both the visual bounds and the outline of + * the text. + * + * @since 1.3 + */ + public static final TextAttribute INPUT_METHOD_UNDERLINE = new TextAttribute("input method underline"); + + /** + * Single pixel solid low underline. + * + * @see #INPUT_METHOD_UNDERLINE + * @since 1.3 + */ + public static final Integer UNDERLINE_LOW_ONE_PIXEL = Integer.valueOf(1); + + /** + * Double pixel solid low underline. + * + * @see #INPUT_METHOD_UNDERLINE + * @since 1.3 + */ + public static final Integer UNDERLINE_LOW_TWO_PIXEL = Integer.valueOf(2); + + /** + * Single pixel dotted low underline. + * + * @see #INPUT_METHOD_UNDERLINE + * @since 1.3 + */ + public static final Integer UNDERLINE_LOW_DOTTED = Integer.valueOf(3); + + /** + * Double pixel gray low underline. + * + * @see #INPUT_METHOD_UNDERLINE + * @since 1.3 + */ + public static final Integer UNDERLINE_LOW_GRAY = Integer.valueOf(4); + + /** + * Single pixel dashed low underline. + * + * @see #INPUT_METHOD_UNDERLINE + * @since 1.3 + */ + public static final Integer UNDERLINE_LOW_DASHED = Integer.valueOf(5); + + /** + * Attribute key for swapping foreground and background {@code Paints}. Values + * are instances of {@code Boolean}. The default value is {@code false}, + * which means do not swap colors. + * + *

+ * The constant value {@link #SWAP_COLORS_ON} is defined. + * + *

+ * If the {@link #FOREGROUND} attribute is set, its {@code Paint} will be used + * as the background, otherwise the {@code Paint} currently on the + * {@code Graphics} will be used. If the {@link #BACKGROUND} attribute is set, + * its {@code Paint} will be used as the foreground, otherwise the system will + * find a contrasting color to the (resolved) background so that the text will + * be visible. + * + * @see #FOREGROUND + * @see #BACKGROUND + */ + public static final TextAttribute SWAP_COLORS = new TextAttribute("swap_colors"); + + /** + * Swap foreground and background. + * + * @see #SWAP_COLORS + * @since 1.3 + */ + public static final Boolean SWAP_COLORS_ON = Boolean.TRUE; + + /** + * Attribute key for converting ASCII decimal digits to other decimal ranges. + * Values are instances of {@link NumericShaper}. The default is {@code null}, + * which means do not perform numeric shaping. + * + *

+ * When a numeric shaper is defined, the text is first processed by the shaper + * before any other analysis of the text is performed. + * + *

+ * Note: This should have the same value for all the text in the + * paragraph, otherwise the behavior is undetermined. + * + * @see NumericShaper + * @since 1.4 + */ + public static final TextAttribute NUMERIC_SHAPING = new TextAttribute("numeric_shaping"); + + /** + * Attribute key to request kerning. Values are instances of + * {@code Integer}. The default value is {@code 0}, which does not + * request kerning. + * + *

+ * The constant value {@link #KERNING_ON} is provided. + * + *

+ * The default advances of single characters are not appropriate for some + * character sequences, for example "To" or "AWAY". Without kerning the adjacent + * characters appear to be separated by too much space. Kerning causes selected + * sequences of characters to be spaced differently for a more pleasing visual + * appearance. + * + * @since 1.6 + */ + public static final TextAttribute KERNING = new TextAttribute("kerning"); + + /** + * Request standard kerning. + * + * @see #KERNING + * @since 1.6 + */ + public static final Integer KERNING_ON = Integer.valueOf(1); + + /** + * Attribute key for enabling optional ligatures. Values are instances of + * {@code Integer}. The default value is {@code 0}, which means do not + * use optional ligatures. + * + *

+ * The constant value {@link #LIGATURES_ON} is defined. + * + *

+ * Ligatures required by the writing system are always enabled. + * + * @since 1.6 + */ + public static final TextAttribute LIGATURES = new TextAttribute("ligatures"); + + /** + * Request standard optional ligatures. + * + * @see #LIGATURES + * @since 1.6 + */ + public static final Integer LIGATURES_ON = Integer.valueOf(1); + + /** + * Attribute key to control tracking. Values are instances of + * {@code Number}. The default value is {@code 0}, which means no + * additional tracking. + * + *

+ * The constant values {@link #TRACKING_TIGHT} and {@link #TRACKING_LOOSE} are + * provided. + * + *

+ * The tracking value is multiplied by the font point size and passed through + * the font transform to determine an additional amount to add to the advance of + * each glyph cluster. Positive tracking values will inhibit formation of + * optional ligatures. Tracking values are typically between {@code -0.1} and + * {@code 0.3}; values outside this range are generally not desirable. + * + * @since 1.6 + */ + public static final TextAttribute TRACKING = new TextAttribute("tracking"); + + /** + * Perform tight tracking. + * + * @see #TRACKING + * @since 1.6 + */ + public static final Float TRACKING_TIGHT = Float.valueOf(-.04f); + + /** + * Perform loose tracking. + * + * @see #TRACKING + * @since 1.6 + */ + public static final Float TRACKING_LOOSE = Float.valueOf(.04f); +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/BMPSet.java b/src/main/java/jdk_internal/bidi/icu/impl/BMPSet.java new file mode 100755 index 00000000..c7a9999d --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/BMPSet.java @@ -0,0 +1,530 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ****************************************************************************** + * + * Copyright (C) 2009-2014, International Business Machines + * Corporation and others. All Rights Reserved. + * + ****************************************************************************** + */ + +package jdk_internal.bidi.icu.impl; + +import jdk_internal.bidi.icu.text.UnicodeSet.SpanCondition; +import jdk_internal.bidi.icu.util.OutputInt; + +/** + * Helper class for frozen UnicodeSets, implements contains() and span() + * optimized for BMP code points. + * + * Latin-1: Look up bytes. 2-byte characters: Bits organized vertically. 3-byte + * characters: Use zero/one/mixed data per 64-block in U+0000..U+FFFF, with + * mixed for illegal ranges. Supplementary characters: Call contains() on the + * parent set. + */ +public final class BMPSet { + + /** + * One boolean ('true' or 'false') per Latin-1 character. + */ + private boolean[] latin1Contains; + + /** + * One bit per code point from U+0000..U+07FF. The bits are organized + * vertically; consecutive code points correspond to the same bit positions in + * consecutive table words. With code point parts lead=c{10..6} trail=c{5..0} it + * is set.contains(c)==(table7FF[trail] bit lead) + * + * Bits for 0..7F (non-shortest forms) are set to the result of contains(FFFD) + * for faster validity checking at runtime. + */ + private int[] table7FF; + + /** + * One bit per 64 BMP code points. The bits are organized vertically; + * consecutive 64-code point blocks correspond to the same bit position in + * consecutive table words. With code point parts lead=c{15..12} t1=c{11..6} + * test bits (lead+16) and lead in bmpBlockBits[t1]. If the upper bit is 0, then + * the lower bit indicates if contains(c) for all code points in the 64-block. + * If the upper bit is 1, then the block is mixed and set.contains(c) must be + * called. + * + * Bits for 0..7FF (non-shortest forms) and D800..DFFF are set to the result of + * contains(FFFD) for faster validity checking at runtime. + */ + private int[] bmpBlockBits; + + /** + * Inversion list indexes for restricted binary searches in findCodePoint(), + * from findCodePoint(U+0800, U+1000, U+2000, .., U+F000, U+10000). U+0800 is + * the first 3-byte-UTF-8 code point. Code points below U+0800 are always looked + * up in the bit tables. The last pair of indexes is for finding supplementary + * code points. + */ + private int[] list4kStarts; + + /** + * The inversion list of the parent set, for the slower contains() + * implementation for mixed BMP blocks and for supplementary code points. The + * list is terminated with list[listLength-1]=0x110000. + */ + private final int[] list; + private final int listLength; // length used; list may be longer to minimize reallocs + + public BMPSet(final int[] parentList, int parentListLength) { + list = parentList; + listLength = parentListLength; + latin1Contains = new boolean[0x100]; + table7FF = new int[64]; + bmpBlockBits = new int[64]; + list4kStarts = new int[18]; + + /* + * Set the list indexes for binary searches for U+0800, U+1000, U+2000, .., + * U+F000, U+10000. U+0800 is the first 3-byte-UTF-8 code point. Lower code + * points are looked up in the bit tables. The last pair of indexes is for + * finding supplementary code points. + */ + list4kStarts[0] = findCodePoint(0x800, 0, listLength - 1); + int i; + for (i = 1; i <= 0x10; ++i) { + list4kStarts[i] = findCodePoint(i << 12, list4kStarts[i - 1], listLength - 1); + } + list4kStarts[0x11] = listLength - 1; + + initBits(); + } + + public boolean contains(int c) { + if (c <= 0xff) { + return (latin1Contains[c]); + } else if (c <= 0x7ff) { + return ((table7FF[c & 0x3f] & (1 << (c >> 6))) != 0); + } else if (c < 0xd800 || (c >= 0xe000 && c <= 0xffff)) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + return (0 != twoBits); + } else { + // Look up the code point in its 4k block of code points. + return containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1]); + } + } else if (c <= 0x10ffff) { + // surrogate or supplementary code point + return containsSlow(c, list4kStarts[0xd], list4kStarts[0x11]); + } else { + // Out-of-range code points get false, consistent with long-standing + // behavior of UnicodeSet.contains(c). + return false; + } + } + + /** + * Span the initial substring for which each character c has + * spanCondition==contains(c). It must be spanCondition==0 or 1. + * + * @param start The start index + * @param outCount If not null: Receives the number of code points in the span. + * @return the limit (exclusive end) of the span + * + * NOTE: to reduce the overhead of function call to contains(c), it is + * manually inlined here. Check for sufficient length for trail unit for + * each surrogate pair. Handle single surrogates as surrogate code + * points as usual in ICU. + */ + public final int span(CharSequence s, int start, SpanCondition spanCondition, OutputInt outCount) { + char c, c2; + int i = start; + int limit = s.length(); + int numSupplementary = 0; + if (SpanCondition.NOT_CONTAINED != spanCondition) { + // span + while (i < limit) { + c = s.charAt(i); + if (c <= 0xff) { + if (!latin1Contains[c]) { + break; + } + } else if (c <= 0x7ff) { + if ((table7FF[c & 0x3f] & (1 << (c >> 6))) == 0) { + break; + } + } else if (c < 0xd800 || c >= 0xdc00 || (i + 1) == limit || (c2 = s.charAt(i + 1)) < 0xdc00 + || c2 >= 0xe000) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + if (twoBits == 0) { + break; + } + } else { + // Look up the code point in its 4k block of code points. + if (!containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1])) { + break; + } + } + } else { + // surrogate pair + int supplementary = UCharacterProperty.getRawSupplementary(c, c2); + if (!containsSlow(supplementary, list4kStarts[0x10], list4kStarts[0x11])) { + break; + } + ++numSupplementary; + ++i; + } + ++i; + } + } else { + // span not + while (i < limit) { + c = s.charAt(i); + if (c <= 0xff) { + if (latin1Contains[c]) { + break; + } + } else if (c <= 0x7ff) { + if ((table7FF[c & 0x3f] & (1 << (c >> 6))) != 0) { + break; + } + } else if (c < 0xd800 || c >= 0xdc00 || (i + 1) == limit || (c2 = s.charAt(i + 1)) < 0xdc00 + || c2 >= 0xe000) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + if (twoBits != 0) { + break; + } + } else { + // Look up the code point in its 4k block of code points. + if (containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1])) { + break; + } + } + } else { + // surrogate pair + int supplementary = UCharacterProperty.getRawSupplementary(c, c2); + if (containsSlow(supplementary, list4kStarts[0x10], list4kStarts[0x11])) { + break; + } + ++numSupplementary; + ++i; + } + ++i; + } + } + if (outCount != null) { + int spanLength = i - start; + outCount.value = spanLength - numSupplementary; // number of code points + } + return i; + } + + /** + * Symmetrical with span(). Span the trailing substring for which each character + * c has spanCondition==contains(c). It must be s.length >= limit and + * spanCondition==0 or 1. + * + * @return The string index which starts the span (i.e. inclusive). + */ + public final int spanBack(CharSequence s, int limit, SpanCondition spanCondition) { + char c, c2; + + if (SpanCondition.NOT_CONTAINED != spanCondition) { + // span + for (;;) { + c = s.charAt(--limit); + if (c <= 0xff) { + if (!latin1Contains[c]) { + break; + } + } else if (c <= 0x7ff) { + if ((table7FF[c & 0x3f] & (1 << (c >> 6))) == 0) { + break; + } + } else if (c < 0xd800 || c < 0xdc00 || 0 == limit || (c2 = s.charAt(limit - 1)) < 0xd800 + || c2 >= 0xdc00) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + if (twoBits == 0) { + break; + } + } else { + // Look up the code point in its 4k block of code points. + if (!containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1])) { + break; + } + } + } else { + // surrogate pair + int supplementary = UCharacterProperty.getRawSupplementary(c2, c); + if (!containsSlow(supplementary, list4kStarts[0x10], list4kStarts[0x11])) { + break; + } + --limit; + } + if (0 == limit) { + return 0; + } + } + } else { + // span not + for (;;) { + c = s.charAt(--limit); + if (c <= 0xff) { + if (latin1Contains[c]) { + break; + } + } else if (c <= 0x7ff) { + if ((table7FF[c & 0x3f] & (1 << (c >> 6))) != 0) { + break; + } + } else if (c < 0xd800 || c < 0xdc00 || 0 == limit || (c2 = s.charAt(limit - 1)) < 0xd800 + || c2 >= 0xdc00) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + if (twoBits != 0) { + break; + } + } else { + // Look up the code point in its 4k block of code points. + if (containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1])) { + break; + } + } + } else { + // surrogate pair + int supplementary = UCharacterProperty.getRawSupplementary(c2, c); + if (containsSlow(supplementary, list4kStarts[0x10], list4kStarts[0x11])) { + break; + } + --limit; + } + if (0 == limit) { + return 0; + } + } + } + return limit + 1; + } + + /** + * Set bits in a bit rectangle in "vertical" bit organization. + * start> 6; // Named for UTF-8 2-byte lead byte with upper 5 bits. + int trail = start & 0x3f; // Named for UTF-8 2-byte trail byte with lower 6 bits. + + // Set one bit indicating an all-one block. + int bits = 1 << lead; + if ((start + 1) == limit) { // Single-character shortcut. + table[trail] |= bits; + return; + } + + int limitLead = limit >> 6; + int limitTrail = limit & 0x3f; + + if (lead == limitLead) { + // Partial vertical bit column. + while (trail < limitTrail) { + table[trail++] |= bits; + } + } else { + // Partial vertical bit column, + // followed by a bit rectangle, + // followed by another partial vertical bit column. + if (trail > 0) { + do { + table[trail++] |= bits; + } while (trail < 64); + ++lead; + } + if (lead < limitLead) { + bits = ~((1 << lead) - 1); + if (limitLead < 0x20) { + bits &= (1 << limitLead) - 1; + } + for (trail = 0; trail < 64; ++trail) { + table[trail] |= bits; + } + } + // limit<=0x800. If limit==0x800 then limitLead=32 and limitTrail=0. + // In that case, bits=1<= 0x100) { + break; + } + do { + latin1Contains[start++] = true; + } while (start < limit && start < 0x100); + } while (limit <= 0x100); + + // Set table7FF[]. + while (start < 0x800) { + set32x64Bits(table7FF, start, limit <= 0x800 ? limit : 0x800); + if (limit > 0x800) { + start = 0x800; + break; + } + + start = list[listIndex++]; + if (listIndex < listLength) { + limit = list[listIndex++]; + } else { + limit = 0x110000; + } + } + + // Set bmpBlockBits[]. + int minStart = 0x800; + while (start < 0x10000) { + if (limit > 0x10000) { + limit = 0x10000; + } + + if (start < minStart) { + start = minStart; + } + if (start < limit) { // Else: Another range entirely in a known mixed-value block. + if (0 != (start & 0x3f)) { + // Mixed-value block of 64 code points. + start >>= 6; + bmpBlockBits[start & 0x3f] |= 0x10001 << (start >> 6); + start = (start + 1) << 6; // Round up to the next block boundary. + minStart = start; // Ignore further ranges in this block. + } + if (start < limit) { + if (start < (limit & ~0x3f)) { + // Multiple all-ones blocks of 64 code points each. + set32x64Bits(bmpBlockBits, start >> 6, limit >> 6); + } + + if (0 != (limit & 0x3f)) { + // Mixed-value block of 64 code points. + limit >>= 6; + bmpBlockBits[limit & 0x3f] |= 0x10001 << (limit >> 6); + limit = (limit + 1) << 6; // Round up to the next block boundary. + minStart = limit; // Ignore further ranges in this block. + } + } + } + + if (limit == 0x10000) { + break; + } + + start = list[listIndex++]; + if (listIndex < listLength) { + limit = list[listIndex++]; + } else { + limit = 0x110000; + } + } + } + + /** + * Same as UnicodeSet.findCodePoint(int c) except that the binary search is + * restricted for finding code points in a certain range. + * + * For restricting the search for finding in the range start..end, pass in + * lo=findCodePoint(start) and hi=findCodePoint(end) with 0<=lo<=hi= hi || c >= list[hi - 1]) + return hi; + // invariant: c >= list[lo] + // invariant: c < list[hi] + for (;;) { + int i = (lo + hi) >>> 1; + if (i == lo) { + break; // Found! + } else if (c < list[i]) { + hi = i; + } else { + lo = i; + } + } + return hi; + } + + private final boolean containsSlow(int c, int lo, int hi) { + return (0 != (findCodePoint(c, lo, hi) & 1)); + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/CharTrie.java b/src/main/java/jdk_internal/bidi/icu/impl/CharTrie.java new file mode 100755 index 00000000..aab129b7 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/CharTrie.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ****************************************************************************** + * Copyright (C) 1996-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ****************************************************************************** + */ + +package jdk_internal.bidi.icu.impl; + +import java.io.DataInputStream; +import java.io.InputStream; + +import jdk_internal.bidi.icu.text.UTF16; + +import java.io.IOException; + +/** + * Trie implementation which stores data in char, 16 bits. + * + * @author synwee + * @see com.ibm.icu.impl.Trie + * @since release 2.1, Jan 01 2002 + */ + +// note that i need to handle the block calculations later, since chartrie +// in icu4c uses the same index array. +public class CharTrie extends Trie { + // public constructors --------------------------------------------- + + /** + *

+ * Creates a new Trie with the settings for the trie data. + *

+ *

+ * Unserialize the 32-bit-aligned input stream and use the data for the trie. + *

+ * + * @param inputStream file input stream to a ICU data file, containing the + * trie + * @param dataManipulate object which provides methods to parse the char data + * @throws IOException thrown when data reading fails + * @draft 2.1 + */ + public CharTrie(InputStream inputStream, DataManipulate dataManipulate) throws IOException { + super(inputStream, dataManipulate); + + if (!isCharTrie()) { + throw new IllegalArgumentException("Data given does not belong to a char trie."); + } + } + + // public methods -------------------------------------------------- + + /** + * Gets the value associated with the codepoint. If no value is associated with + * the codepoint, a default value will be returned. + * + * @param ch codepoint + * @return offset to data + */ + public final char getCodePointValue(int ch) { + int offset; + + // fastpath for U+0000..U+D7FF + if (0 <= ch && ch < UTF16.LEAD_SURROGATE_MIN_VALUE) { + // copy of getRawOffset() + offset = (m_index_[ch >> INDEX_STAGE_1_SHIFT_] << INDEX_STAGE_2_SHIFT_) + (ch & INDEX_STAGE_3_MASK_); + return m_data_[offset]; + } + + // handle U+D800..U+10FFFF + offset = getCodePointOffset(ch); + + // return -1 if there is an error, in this case we return the default + // value: m_initialValue_ + return (offset >= 0) ? m_data_[offset] : m_initialValue_; + } + + /** + * Gets the value to the data which this lead surrogate character points to. + * Returned data may contain folding offset information for the next trailing + * surrogate character. This method does not guarantee correct results for trail + * surrogates. + * + * @param ch lead surrogate character + * @return data value + */ + public final char getLeadValue(char ch) { + return m_data_[getLeadOffset(ch)]; + } + + // protected methods ----------------------------------------------- + + /** + *

+ * Parses the input stream and stores its trie content into a index and data + * array + *

+ * + * @param inputStream data input stream containing trie data + * @exception IOException thrown when data reading fails + */ + protected final void unserialize(InputStream inputStream) throws IOException { + DataInputStream input = new DataInputStream(inputStream); + int indexDataLength = m_dataOffset_ + m_dataLength_; + m_index_ = new char[indexDataLength]; + for (int i = 0; i < indexDataLength; i++) { + m_index_[i] = input.readChar(); + } + m_data_ = m_index_; + m_initialValue_ = m_data_[m_dataOffset_]; + } + + /** + * Gets the offset to the data which the surrogate pair points to. + * + * @param lead lead surrogate + * @param trail trailing surrogate + * @return offset to data + * @draft 2.1 + */ + protected final int getSurrogateOffset(char lead, char trail) { + if (m_dataManipulate_ == null) { + throw new NullPointerException("The field DataManipulate in this Trie is null"); + } + + // get fold position for the next trail surrogate + int offset = m_dataManipulate_.getFoldingOffset(getLeadValue(lead)); + + // get the real data from the folded lead/trail units + if (offset > 0) { + return getRawOffset(offset, (char) (trail & SURROGATE_MASK_)); + } + + // return -1 if there is an error, in this case we return the default + // value: m_initialValue_ + return -1; + } + + // private data members -------------------------------------------- + + /** + * Default value + */ + private char m_initialValue_; + /** + * Array of char data + */ + private char m_data_[]; +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/CharacterIteratorWrapper.java b/src/main/java/jdk_internal/bidi/icu/impl/CharacterIteratorWrapper.java new file mode 100755 index 00000000..7d6fcede --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/CharacterIteratorWrapper.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.impl; + +import jdk_internal.bidi.CharacterIterator; +import jdk_internal.bidi.icu.text.UCharacterIterator; + +/** + * This class is a wrapper around CharacterIterator and implements the + * UCharacterIterator protocol + * + * @author ram + */ + +public class CharacterIteratorWrapper extends UCharacterIterator { + + private CharacterIterator iterator; + + public CharacterIteratorWrapper(CharacterIterator iter) { + if (iter == null) { + throw new IllegalArgumentException(); + } + iterator = iter; + } + + /** + * @see UCharacterIterator#current() + */ + public int current() { + int c = iterator.current(); + if (c == CharacterIterator.DONE) { + return DONE; + } + return c; + } + + /** + * @see UCharacterIterator#getLength() + */ + public int getLength() { + return (iterator.getEndIndex() - iterator.getBeginIndex()); + } + + /** + * @see UCharacterIterator#getIndex() + */ + public int getIndex() { + return iterator.getIndex(); + } + + /** + * @see UCharacterIterator#next() + */ + public int next() { + int i = iterator.current(); + iterator.next(); + if (i == CharacterIterator.DONE) { + return DONE; + } + return i; + } + + /** + * @see UCharacterIterator#previous() + */ + public int previous() { + int i = iterator.previous(); + if (i == CharacterIterator.DONE) { + return DONE; + } + return i; + } + + /** + * @see UCharacterIterator#setIndex(int) + */ + public void setIndex(int index) { + iterator.setIndex(index); + } + + /** + * @see UCharacterIterator#getText(char[]) + */ + public int getText(char[] fillIn, int offset) { + int length = iterator.getEndIndex() - iterator.getBeginIndex(); + int currentIndex = iterator.getIndex(); + if (offset < 0 || offset + length > fillIn.length) { + throw new IndexOutOfBoundsException(Integer.toString(length)); + } + + for (char ch = iterator.first(); ch != CharacterIterator.DONE; ch = iterator.next()) { + fillIn[offset++] = ch; + } + iterator.setIndex(currentIndex); + + return length; + } + + /** + * Creates a clone of this iterator. Clones the underlying character iterator. + * + * @see UCharacterIterator#clone() + */ + public Object clone() { + try { + CharacterIteratorWrapper result = (CharacterIteratorWrapper) super.clone(); + result.iterator = (CharacterIterator) this.iterator.clone(); + return result; + } catch (CloneNotSupportedException e) { + return null; // only invoked if bad underlying character iterator + } + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/ICUBinary.java b/src/main/java/jdk_internal/bidi/icu/impl/ICUBinary.java new file mode 100755 index 00000000..dbbe0b39 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/ICUBinary.java @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 1996-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.impl; + +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; + +import jdk_internal.bidi.icu.util.VersionInfo; +import net.lax1dude.eaglercraft.v1_8.EagRuntime; + +public final class ICUBinary { + + private static final class IsAcceptable implements Authenticate { + @Override + public boolean isDataVersionAcceptable(byte version[]) { + return version[0] == 1; + } + } + + // public inner interface ------------------------------------------------ + + /** + * Special interface for data authentication + */ + public static interface Authenticate { + /** + * Method used in ICUBinary.readHeader() to provide data format authentication. + * + * @param version version of the current data + * @return true if dataformat is an acceptable version, false otherwise + */ + public boolean isDataVersionAcceptable(byte version[]); + } + + // public methods -------------------------------------------------------- + + /** + * Loads an ICU binary data file and returns it as a ByteBuffer. The buffer + * contents is normally read-only, but its position etc. can be modified. + * + * @param itemPath Relative ICU data item path, for example "root.res" or + * "coll/ucadata.icu". + * @return The data as a read-only ByteBuffer. + */ + public static ByteBuffer getRequiredData(String itemPath) { + try (InputStream is = EagRuntime.getRequiredResourceStream(itemPath)) { + + // is.available() may return 0, or 1, or the total number of bytes in the + // stream, + // or some other number. + // Do not try to use is.available() == 0 to find the end of the stream! + byte[] bytes; + int avail = is.available(); + if (avail > 32) { + // There are more bytes available than just the ICU data header length. + // With luck, it is the total number of bytes. + bytes = new byte[avail]; + } else { + bytes = new byte[128]; // empty .res files are even smaller + } + // Call is.read(...) until one returns a negative value. + int length = 0; + for (;;) { + if (length < bytes.length) { + int numRead = is.read(bytes, length, bytes.length - length); + if (numRead < 0) { + break; // end of stream + } + length += numRead; + } else { + // See if we are at the end of the stream before we grow the array. + int nextByte = is.read(); + if (nextByte < 0) { + break; + } + int capacity = 2 * bytes.length; + if (capacity < 128) { + capacity = 128; + } else if (capacity < 0x4000) { + capacity *= 2; // Grow faster until we reach 16kB. + } + bytes = Arrays.copyOf(bytes, capacity); + bytes[length++] = (byte) nextByte; + } + } + return ByteBuffer.wrap(bytes, 0, length); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + /** + * Same as readHeader(), but returns a VersionInfo rather than a compact int. + */ + public static VersionInfo readHeaderAndDataVersion(ByteBuffer bytes, int dataFormat, Authenticate authenticate) + throws IOException { + return getVersionInfoFromCompactInt(readHeader(bytes, dataFormat, authenticate)); + } + + private static final byte BIG_ENDIAN_ = 1; + + public static final byte[] readHeader(InputStream inputStream, byte dataFormatIDExpected[], + Authenticate authenticate) throws IOException { + DataInputStream input = new DataInputStream(inputStream); + char headersize = input.readChar(); + int readcount = 2; + // reading the header format + byte magic1 = input.readByte(); + readcount++; + byte magic2 = input.readByte(); + readcount++; + if (magic1 != MAGIC1 || magic2 != MAGIC2) { + throw new IOException(MAGIC_NUMBER_AUTHENTICATION_FAILED_); + } + + input.readChar(); // reading size + readcount += 2; + input.readChar(); // reading reserved word + readcount += 2; + byte bigendian = input.readByte(); + readcount++; + byte charset = input.readByte(); + readcount++; + byte charsize = input.readByte(); + readcount++; + input.readByte(); // reading reserved byte + readcount++; + + byte dataFormatID[] = new byte[4]; + input.readFully(dataFormatID); + readcount += 4; + byte dataVersion[] = new byte[4]; + input.readFully(dataVersion); + readcount += 4; + byte unicodeVersion[] = new byte[4]; + input.readFully(unicodeVersion); + readcount += 4; + if (headersize < readcount) { + throw new IOException("Internal Error: Header size error"); + } + input.skipBytes(headersize - readcount); + + if (bigendian != BIG_ENDIAN_ || charset != CHAR_SET_ || charsize != CHAR_SIZE_ + || !Arrays.equals(dataFormatIDExpected, dataFormatID) + || (authenticate != null && !authenticate.isDataVersionAcceptable(dataVersion))) { + throw new IOException(HEADER_AUTHENTICATION_FAILED_); + } + return unicodeVersion; + } + + /** + * Reads an ICU data header, checks the data format, and returns the data + * version. + * + *

+ * Assumes that the ByteBuffer position is 0 on input. The buffer byte order is + * set according to the data. The buffer position is advanced past the header + * (including UDataInfo and comment). + * + *

+ * See C++ ucmndata.h and unicode/udata.h. + * + * @return dataVersion + * @throws IOException if this is not a valid ICU data item of the expected + * dataFormat + */ + public static int readHeader(ByteBuffer bytes, int dataFormat, Authenticate authenticate) throws IOException { + assert bytes.position() == 0; + byte magic1 = bytes.get(2); + byte magic2 = bytes.get(3); + if (magic1 != MAGIC1 || magic2 != MAGIC2) { + throw new IOException(MAGIC_NUMBER_AUTHENTICATION_FAILED_); + } + + byte isBigEndian = bytes.get(8); + byte charsetFamily = bytes.get(9); + byte sizeofUChar = bytes.get(10); + if (isBigEndian < 0 || 1 < isBigEndian || charsetFamily != CHAR_SET_ || sizeofUChar != CHAR_SIZE_) { + throw new IOException(HEADER_AUTHENTICATION_FAILED_); + } + bytes.order(isBigEndian != 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN); + + int headerSize = bytes.getChar(0); + int sizeofUDataInfo = bytes.getChar(4); + if (sizeofUDataInfo < 20 || headerSize < (sizeofUDataInfo + 4)) { + throw new IOException("Internal Error: Header size error"); + } + // TODO: Change Authenticate to take int major, int minor, int milli, int micro + // to avoid array allocation. + byte[] formatVersion = new byte[] { bytes.get(16), bytes.get(17), bytes.get(18), bytes.get(19) }; + if (bytes.get(12) != (byte) (dataFormat >> 24) || bytes.get(13) != (byte) (dataFormat >> 16) + || bytes.get(14) != (byte) (dataFormat >> 8) || bytes.get(15) != (byte) dataFormat + || (authenticate != null && !authenticate.isDataVersionAcceptable(formatVersion))) { + throw new IOException(HEADER_AUTHENTICATION_FAILED_ + + String.format("; data format %02x%02x%02x%02x, format version %d.%d.%d.%d", bytes.get(12), + bytes.get(13), bytes.get(14), bytes.get(15), formatVersion[0] & 0xff, + formatVersion[1] & 0xff, formatVersion[2] & 0xff, formatVersion[3] & 0xff)); + } + + bytes.position(headerSize); + return // dataVersion + ((int) bytes.get(20) << 24) | ((bytes.get(21) & 0xff) << 16) | ((bytes.get(22) & 0xff) << 8) + | (bytes.get(23) & 0xff); + } + + public static void skipBytes(ByteBuffer bytes, int skipLength) { + if (skipLength > 0) { + bytes.position(bytes.position() + skipLength); + } + } + + public static byte[] getBytes(ByteBuffer bytes, int length, int additionalSkipLength) { + byte[] dest = new byte[length]; + bytes.get(dest); + if (additionalSkipLength > 0) { + skipBytes(bytes, additionalSkipLength); + } + return dest; + } + + public static String getString(ByteBuffer bytes, int length, int additionalSkipLength) { + CharSequence cs = bytes.asCharBuffer(); + String s = cs.subSequence(0, length).toString(); + skipBytes(bytes, length * 2 + additionalSkipLength); + return s; + } + + public static char[] getChars(ByteBuffer bytes, int length, int additionalSkipLength) { + char[] dest = new char[length]; + bytes.asCharBuffer().get(dest); + skipBytes(bytes, length * 2 + additionalSkipLength); + return dest; + } + + public static int[] getInts(ByteBuffer bytes, int length, int additionalSkipLength) { + int[] dest = new int[length]; + bytes.asIntBuffer().get(dest); + skipBytes(bytes, length * 4 + additionalSkipLength); + return dest; + } + + /** + * Returns a VersionInfo for the bytes in the compact version integer. + */ + public static VersionInfo getVersionInfoFromCompactInt(int version) { + return VersionInfo.getInstance(version >>> 24, (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); + } + + // private variables ------------------------------------------------- + + /** + * Magic numbers to authenticate the data file + */ + private static final byte MAGIC1 = (byte) 0xda; + private static final byte MAGIC2 = (byte) 0x27; + + /** + * File format authentication values + */ + private static final byte CHAR_SET_ = 0; + private static final byte CHAR_SIZE_ = 2; + + /** + * Error messages + */ + private static final String MAGIC_NUMBER_AUTHENTICATION_FAILED_ = "ICUBinary data file error: Magic number authentication failed"; + private static final String HEADER_AUTHENTICATION_FAILED_ = "ICUBinary data file error: Header authentication failed"; +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/Norm2AllModes.java b/src/main/java/jdk_internal/bidi/icu/impl/Norm2AllModes.java new file mode 100755 index 00000000..aaabf2f0 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/Norm2AllModes.java @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2014, International Business Machines + * Corporation and others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.impl; + +import java.io.IOException; + +import jdk_internal.bidi.icu.text.Normalizer2; + +public final class Norm2AllModes { + // Public API dispatch via Normalizer2 subclasses -------------------------- *** + + // Normalizer2 implementation for the old UNORM_NONE. + public static final class NoopNormalizer2 extends Normalizer2 { + @Override + public StringBuilder normalize(CharSequence src, StringBuilder dest) { + if (dest != src) { + dest.setLength(0); + return dest.append(src); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public Appendable normalize(CharSequence src, Appendable dest) { + if (dest != src) { + try { + return dest.append(src); + } catch (IOException e) { + throw new InternalError(e.toString(), e); + } + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) { + if (first != second) { + return first.append(second); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public StringBuilder append(StringBuilder first, CharSequence second) { + if (first != second) { + return first.append(second); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public String getDecomposition(int c) { + return null; + } + + // No need to override the default getRawDecomposition(). + @Override + public boolean isNormalized(CharSequence s) { + return true; + } + + @Override + public int spanQuickCheckYes(CharSequence s) { + return s.length(); + } + + @Override + public boolean hasBoundaryBefore(int c) { + return true; + } + } + + // Intermediate class: + // Has NormalizerImpl and does boilerplate argument checking and setup. + public abstract static class Normalizer2WithImpl extends Normalizer2 { + public Normalizer2WithImpl(NormalizerImpl ni) { + impl = ni; + } + + // normalize + @Override + public StringBuilder normalize(CharSequence src, StringBuilder dest) { + if (dest == src) { + throw new IllegalArgumentException(); + } + dest.setLength(0); + normalize(src, new NormalizerImpl.ReorderingBuffer(impl, dest, src.length())); + return dest; + } + + @Override + public Appendable normalize(CharSequence src, Appendable dest) { + if (dest == src) { + throw new IllegalArgumentException(); + } + NormalizerImpl.ReorderingBuffer buffer = new NormalizerImpl.ReorderingBuffer(impl, dest, src.length()); + normalize(src, buffer); + buffer.flush(); + return dest; + } + + protected abstract void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer); + + // normalize and append + @Override + public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) { + return normalizeSecondAndAppend(first, second, true); + } + + @Override + public StringBuilder append(StringBuilder first, CharSequence second) { + return normalizeSecondAndAppend(first, second, false); + } + + public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second, boolean doNormalize) { + if (first == second) { + throw new IllegalArgumentException(); + } + normalizeAndAppend(second, doNormalize, + new NormalizerImpl.ReorderingBuffer(impl, first, first.length() + second.length())); + return first; + } + + protected abstract void normalizeAndAppend(CharSequence src, boolean doNormalize, + NormalizerImpl.ReorderingBuffer buffer); + + @Override + public String getDecomposition(int c) { + return impl.getDecomposition(c); + } + + @Override + public int getCombiningClass(int c) { + return impl.getCC(impl.getNorm16(c)); + } + + // quick checks + @Override + public boolean isNormalized(CharSequence s) { + return s.length() == spanQuickCheckYes(s); + } + + public final NormalizerImpl impl; + } + + public static final class DecomposeNormalizer2 extends Normalizer2WithImpl { + public DecomposeNormalizer2(NormalizerImpl ni) { + super(ni); + } + + @Override + protected void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer) { + impl.decompose(src, 0, src.length(), buffer); + } + + @Override + protected void normalizeAndAppend(CharSequence src, boolean doNormalize, + NormalizerImpl.ReorderingBuffer buffer) { + impl.decomposeAndAppend(src, doNormalize, buffer); + } + + @Override + public int spanQuickCheckYes(CharSequence s) { + return impl.decompose(s, 0, s.length(), null); + } + + @Override + public boolean hasBoundaryBefore(int c) { + return impl.hasDecompBoundaryBefore(c); + } + } + + public static final class ComposeNormalizer2 extends Normalizer2WithImpl { + public ComposeNormalizer2(NormalizerImpl ni, boolean fcc) { + super(ni); + onlyContiguous = fcc; + } + + @Override + protected void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer) { + impl.compose(src, 0, src.length(), onlyContiguous, true, buffer); + } + + @Override + protected void normalizeAndAppend(CharSequence src, boolean doNormalize, + NormalizerImpl.ReorderingBuffer buffer) { + impl.composeAndAppend(src, doNormalize, onlyContiguous, buffer); + } + + @Override + public boolean isNormalized(CharSequence s) { + // 5: small destCapacity for substring normalization + return impl.compose(s, 0, s.length(), onlyContiguous, false, + new NormalizerImpl.ReorderingBuffer(impl, new StringBuilder(), 5)); + } + + @Override + public int spanQuickCheckYes(CharSequence s) { + return impl.composeQuickCheck(s, 0, s.length(), onlyContiguous, true) >>> 1; + } + + @Override + public boolean hasBoundaryBefore(int c) { + return impl.hasCompBoundaryBefore(c); + } + + private final boolean onlyContiguous; + } + + // instance cache ---------------------------------------------------------- *** + + private Norm2AllModes(NormalizerImpl ni) { + impl = ni; + comp = new ComposeNormalizer2(ni, false); + decomp = new DecomposeNormalizer2(ni); + } + + public final NormalizerImpl impl; + public final ComposeNormalizer2 comp; + public final DecomposeNormalizer2 decomp; + + private static Norm2AllModes getInstanceFromSingleton(Norm2AllModesSingleton singleton) { + if (singleton.exception != null) { + throw singleton.exception; + } + return singleton.allModes; + } + + public static Norm2AllModes getNFCInstance() { + return getInstanceFromSingleton(NFCSingleton.INSTANCE); + } + + public static Norm2AllModes getNFKCInstance() { + return getInstanceFromSingleton(NFKCSingleton.INSTANCE); + } + + public static final NoopNormalizer2 NOOP_NORMALIZER2 = new NoopNormalizer2(); + + private static final class Norm2AllModesSingleton { + private Norm2AllModesSingleton(String name) { + try { + @SuppressWarnings("deprecation") + String DATA_FILE_NAME = "/assets/eagler/icudt/" + name + ".nrm"; + NormalizerImpl impl = new NormalizerImpl().load(DATA_FILE_NAME); + allModes = new Norm2AllModes(impl); + } catch (RuntimeException e) { + exception = e; + } + } + + private Norm2AllModes allModes; + private RuntimeException exception; + } + + private static final class NFCSingleton { + private static final Norm2AllModesSingleton INSTANCE = new Norm2AllModesSingleton("nfc"); + } + + private static final class NFKCSingleton { + private static final Norm2AllModesSingleton INSTANCE = new Norm2AllModesSingleton("nfkc"); + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/NormalizerImpl.java b/src/main/java/jdk_internal/bidi/icu/impl/NormalizerImpl.java new file mode 100755 index 00000000..920aa7a0 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/NormalizerImpl.java @@ -0,0 +1,2261 @@ +/* + * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2014, International Business Machines + * Corporation and others. All Rights Reserved. + ******************************************************************************* + */ +package jdk_internal.bidi.icu.impl; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import jdk_internal.bidi.icu.lang.UCharacter; +import jdk_internal.bidi.icu.text.Normalizer2; +import jdk_internal.bidi.icu.text.UTF16; +import jdk_internal.bidi.icu.util.CodePointTrie; +import jdk_internal.bidi.icu.util.VersionInfo; + +// Original filename in ICU4J: Normalizer2Impl.java +public final class NormalizerImpl { + public static final class Hangul { + /* Korean Hangul and Jamo constants */ + public static final int JAMO_L_BASE = 0x1100; /* "lead" jamo */ + public static final int JAMO_V_BASE = 0x1161; /* "vowel" jamo */ + public static final int JAMO_T_BASE = 0x11a7; /* "trail" jamo */ + + public static final int HANGUL_BASE = 0xac00; + public static final int HANGUL_END = 0xd7a3; + + public static final int JAMO_L_COUNT = 19; + public static final int JAMO_V_COUNT = 21; + public static final int JAMO_T_COUNT = 28; + + public static final int HANGUL_COUNT = JAMO_L_COUNT * JAMO_V_COUNT * JAMO_T_COUNT; + public static final int HANGUL_LIMIT = HANGUL_BASE + HANGUL_COUNT; + + public static boolean isHangul(int c) { + return HANGUL_BASE <= c && c < HANGUL_LIMIT; + } + + public static boolean isHangulLV(int c) { + c -= HANGUL_BASE; + return 0 <= c && c < HANGUL_COUNT && c % JAMO_T_COUNT == 0; + } + + /** + * Decomposes c, which must be a Hangul syllable, into buffer and returns the + * length of the decomposition (2 or 3). + */ + public static int decompose(int c, Appendable buffer) { + try { + c -= HANGUL_BASE; + int c2 = c % JAMO_T_COUNT; + c /= JAMO_T_COUNT; + buffer.append((char) (JAMO_L_BASE + c / JAMO_V_COUNT)); + buffer.append((char) (JAMO_V_BASE + c % JAMO_V_COUNT)); + if (c2 == 0) { + return 2; + } else { + buffer.append((char) (JAMO_T_BASE + c2)); + return 3; + } + } catch (IOException e) { + throw new InternalError(e); + } + } + } + + /** + * Writable buffer that takes care of canonical ordering. Its Appendable methods + * behave like the C++ implementation's appendZeroCC() methods. + *

+ * If dest is a StringBuilder, then the buffer writes directly to it. Otherwise, + * the buffer maintains a StringBuilder for intermediate text segments until no + * further changes are necessary and whole segments are appended. append() + * methods that take combining-class values always write to the StringBuilder. + * Other append() methods flush and append to the Appendable. + */ + public static final class ReorderingBuffer implements Appendable { + public ReorderingBuffer(NormalizerImpl ni, Appendable dest, int destCapacity) { + impl = ni; + app = dest; + if (app instanceof StringBuilder) { + appIsStringBuilder = true; + str = (StringBuilder) dest; + // In Java, the constructor subsumes public void init(int destCapacity) + str.ensureCapacity(destCapacity); + reorderStart = 0; + if (str.length() == 0) { + lastCC = 0; + } else { + setIterator(); + lastCC = previousCC(); + // Set reorderStart after the last code point with cc<=1 if there is one. + if (lastCC > 1) { + while (previousCC() > 1) { + } + } + reorderStart = codePointLimit; + } + } else { + appIsStringBuilder = false; + str = new StringBuilder(); + reorderStart = 0; + lastCC = 0; + } + } + + public boolean isEmpty() { + return str.length() == 0; + } + + public int length() { + return str.length(); + } + + public int getLastCC() { + return lastCC; + } + + public StringBuilder getStringBuilder() { + return str; + } + + public boolean equals(CharSequence s, int start, int limit) { + return UTF16Plus.equal(str, 0, str.length(), s, start, limit); + } + + public void append(int c, int cc) { + if (lastCC <= cc || cc == 0) { + str.appendCodePoint(c); + lastCC = cc; + if (cc <= 1) { + reorderStart = str.length(); + } + } else { + insert(c, cc); + } + } + + public void append(CharSequence s, int start, int limit, boolean isNFD, int leadCC, int trailCC) { + if (start == limit) { + return; + } + if (lastCC <= leadCC || leadCC == 0) { + if (trailCC <= 1) { + reorderStart = str.length() + (limit - start); + } else if (leadCC <= 1) { + reorderStart = str.length() + 1; // Ok if not a code point boundary. + } + str.append(s, start, limit); + lastCC = trailCC; + } else { + int c = Character.codePointAt(s, start); + start += Character.charCount(c); + insert(c, leadCC); // insert first code point + while (start < limit) { + c = Character.codePointAt(s, start); + start += Character.charCount(c); + if (start < limit) { + if (isNFD) { + leadCC = getCCFromYesOrMaybe(impl.getNorm16(c)); + } else { + leadCC = impl.getCC(impl.getNorm16(c)); + } + } else { + leadCC = trailCC; + } + append(c, leadCC); + } + } + } + + // The following append() methods work like C++ appendZeroCC(). + // They assume that the cc or trailCC of their input is 0. + // Most of them implement Appendable interface methods. + @Override + public ReorderingBuffer append(char c) { + str.append(c); + lastCC = 0; + reorderStart = str.length(); + return this; + } + + public void appendZeroCC(int c) { + str.appendCodePoint(c); + lastCC = 0; + reorderStart = str.length(); + } + + @Override + public ReorderingBuffer append(CharSequence s) { + if (s.length() != 0) { + str.append(s); + lastCC = 0; + reorderStart = str.length(); + } + return this; + } + + @Override + public ReorderingBuffer append(CharSequence s, int start, int limit) { + if (start != limit) { + str.append(s, start, limit); + lastCC = 0; + reorderStart = str.length(); + } + return this; + } + + /** + * Flushes from the intermediate StringBuilder to the Appendable, if they are + * different objects. Used after recomposition. Must be called at the end when + * writing to a non-StringBuilder Appendable. + */ + public void flush() { + if (appIsStringBuilder) { + reorderStart = str.length(); + } else { + try { + app.append(str); + str.setLength(0); + reorderStart = 0; + } catch (IOException e) { + throw new InternalError(e); // Avoid declaring "throws IOException". + } + } + lastCC = 0; + } + + /** + * Flushes from the intermediate StringBuilder to the Appendable, if they are + * different objects. Then appends the new text to the Appendable or + * StringBuilder. Normally used after quick check loops find a non-empty + * sequence. + */ + public ReorderingBuffer flushAndAppendZeroCC(CharSequence s, int start, int limit) { + if (appIsStringBuilder) { + str.append(s, start, limit); + reorderStart = str.length(); + } else { + try { + app.append(str).append(s, start, limit); + str.setLength(0); + reorderStart = 0; + } catch (IOException e) { + throw new InternalError(e); // Avoid declaring "throws IOException". + } + } + lastCC = 0; + return this; + } + + public void remove() { + str.setLength(0); + lastCC = 0; + reorderStart = 0; + } + + public void removeSuffix(int suffixLength) { + int oldLength = str.length(); + str.delete(oldLength - suffixLength, oldLength); + lastCC = 0; + reorderStart = str.length(); + } + + // Inserts c somewhere before the last character. + // Requires 0 cc;) { + } + // insert c at codePointLimit, after the character with prevCC<=cc + if (c <= 0xffff) { + str.insert(codePointLimit, (char) c); + if (cc <= 1) { + reorderStart = codePointLimit + 1; + } + } else { + str.insert(codePointLimit, Character.toChars(c)); + if (cc <= 1) { + reorderStart = codePointLimit + 2; + } + } + } + + private final NormalizerImpl impl; + private final Appendable app; + private final StringBuilder str; + private final boolean appIsStringBuilder; + private int reorderStart; + private int lastCC; + + // private backward iterator + private void setIterator() { + codePointStart = str.length(); + } + + private void skipPrevious() { // Requires 0= codePointStart) { + return 0; + } + int c = str.codePointBefore(codePointStart); + codePointStart -= Character.charCount(c); + return impl.getCCFromYesOrMaybeCP(c); + } + + private int codePointStart, codePointLimit; + } + + // TODO: Propose as public API on the UTF16 class. + // TODO: Propose widening UTF16 methods that take char to take int. + // TODO: Propose widening UTF16 methods that take String to take CharSequence. + public static final class UTF16Plus { + /** + * Is this code point a lead surrogate (U+d800..U+dbff)? + * + * @param c code unit or code point + * @return true or false + */ + public static boolean isLeadSurrogate(int c) { + return (c & 0xfffffc00) == 0xd800; + } + + /** + * Assuming c is a surrogate code point (UTF16.isSurrogate(c)), is it a lead + * surrogate? + * + * @param c code unit or code point + * @return true or false + */ + public static boolean isSurrogateLead(int c) { + return (c & 0x400) == 0; + } + + /** + * Compares two CharSequence subsequences for binary equality. + * + * @param s1 first sequence + * @param start1 start offset in first sequence + * @param limit1 limit offset in first sequence + * @param s2 second sequence + * @param start2 start offset in second sequence + * @param limit2 limit offset in second sequence + * @return true if s1.subSequence(start1, limit1) contains the same text as + * s2.subSequence(start2, limit2) + */ + public static boolean equal(CharSequence s1, int start1, int limit1, CharSequence s2, int start2, int limit2) { + if ((limit1 - start1) != (limit2 - start2)) { + return false; + } + if (s1 == s2 && start1 == start2) { + return true; + } + while (start1 < limit1) { + if (s1.charAt(start1++) != s2.charAt(start2++)) { + return false; + } + } + return true; + } + } + + public NormalizerImpl() { + } + + private static final class IsAcceptable implements ICUBinary.Authenticate { + public boolean isDataVersionAcceptable(byte version[]) { + return version[0] == 4; + } + } + + private static final IsAcceptable IS_ACCEPTABLE = new IsAcceptable(); + private static final int DATA_FORMAT = 0x4e726d32; // "Nrm2" + + public NormalizerImpl load(ByteBuffer bytes) { + try { + dataVersion = ICUBinary.readHeaderAndDataVersion(bytes, DATA_FORMAT, IS_ACCEPTABLE); + int indexesLength = bytes.getInt() / 4; // inIndexes[IX_NORM_TRIE_OFFSET]/4 + if (indexesLength <= IX_MIN_LCCC_CP) { + throw new InternalError("Normalizer2 data: not enough indexes"); + } + int[] inIndexes = new int[indexesLength]; + inIndexes[0] = indexesLength * 4; + for (int i = 1; i < indexesLength; ++i) { + inIndexes[i] = bytes.getInt(); + } + + minDecompNoCP = inIndexes[IX_MIN_DECOMP_NO_CP]; + minCompNoMaybeCP = inIndexes[IX_MIN_COMP_NO_MAYBE_CP]; + minLcccCP = inIndexes[IX_MIN_LCCC_CP]; + + minYesNo = inIndexes[IX_MIN_YES_NO]; + minYesNoMappingsOnly = inIndexes[IX_MIN_YES_NO_MAPPINGS_ONLY]; + minNoNo = inIndexes[IX_MIN_NO_NO]; + minNoNoCompBoundaryBefore = inIndexes[IX_MIN_NO_NO_COMP_BOUNDARY_BEFORE]; + minNoNoCompNoMaybeCC = inIndexes[IX_MIN_NO_NO_COMP_NO_MAYBE_CC]; + minNoNoEmpty = inIndexes[IX_MIN_NO_NO_EMPTY]; + limitNoNo = inIndexes[IX_LIMIT_NO_NO]; + minMaybeYes = inIndexes[IX_MIN_MAYBE_YES]; + assert ((minMaybeYes & 7) == 0); // 8-aligned for noNoDelta bit fields + centerNoNoDelta = (minMaybeYes >> DELTA_SHIFT) - MAX_DELTA - 1; + + // Read the normTrie. + int offset = inIndexes[IX_NORM_TRIE_OFFSET]; + int nextOffset = inIndexes[IX_EXTRA_DATA_OFFSET]; + int triePosition = bytes.position(); + normTrie = CodePointTrie.Fast16.fromBinary(bytes); + int trieLength = bytes.position() - triePosition; + if (trieLength > (nextOffset - offset)) { + throw new InternalError("Normalizer2 data: not enough bytes for normTrie"); + } + ICUBinary.skipBytes(bytes, (nextOffset - offset) - trieLength); // skip padding after trie bytes + + // Read the composition and mapping data. + offset = nextOffset; + nextOffset = inIndexes[IX_SMALL_FCD_OFFSET]; + int numChars = (nextOffset - offset) / 2; + if (numChars != 0) { + maybeYesCompositions = ICUBinary.getString(bytes, numChars, 0); + extraData = maybeYesCompositions.substring((MIN_NORMAL_MAYBE_YES - minMaybeYes) >> OFFSET_SHIFT); + } + + // smallFCD: new in formatVersion 2 + offset = nextOffset; + smallFCD = new byte[0x100]; + bytes.get(smallFCD); + + return this; + } catch (IOException e) { + throw new InternalError(e); + } + } + + public NormalizerImpl load(String name) { + return load(ICUBinary.getRequiredData(name)); + } + + // The trie stores values for lead surrogate code *units*. + // Surrogate code *points* are inert. + public int getNorm16(int c) { + return UTF16Plus.isLeadSurrogate(c) ? INERT : normTrie.get(c); + } + + public int getRawNorm16(int c) { + return normTrie.get(c); + } + + public boolean isAlgorithmicNoNo(int norm16) { + return limitNoNo <= norm16 && norm16 < minMaybeYes; + } + + public boolean isCompNo(int norm16) { + return minNoNo <= norm16 && norm16 < minMaybeYes; + } + + public boolean isDecompYes(int norm16) { + return norm16 < minYesNo || minMaybeYes <= norm16; + } + + public int getCC(int norm16) { + if (norm16 >= MIN_NORMAL_MAYBE_YES) { + return getCCFromNormalYesOrMaybe(norm16); + } + if (norm16 < minNoNo || limitNoNo <= norm16) { + return 0; + } + return getCCFromNoNo(norm16); + } + + public static int getCCFromNormalYesOrMaybe(int norm16) { + return (norm16 >> OFFSET_SHIFT) & 0xff; + } + + public static int getCCFromYesOrMaybe(int norm16) { + return norm16 >= MIN_NORMAL_MAYBE_YES ? getCCFromNormalYesOrMaybe(norm16) : 0; + } + + public int getCCFromYesOrMaybeCP(int c) { + if (c < minCompNoMaybeCP) { + return 0; + } + return getCCFromYesOrMaybe(getNorm16(c)); + } + + /** + * Returns the FCD data for code point c. + * + * @param c A Unicode code point. + * @return The lccc(c) in bits 15..8 and tccc(c) in bits 7..0. + */ + public int getFCD16(int c) { + if (c < minDecompNoCP) { + return 0; + } else if (c <= 0xffff) { + if (!singleLeadMightHaveNonZeroFCD16(c)) { + return 0; + } + } + return getFCD16FromNormData(c); + } + + /** + * Returns true if the single-or-lead code unit c might have non-zero FCD data. + */ + public boolean singleLeadMightHaveNonZeroFCD16(int lead) { + // 0<=lead<=0xffff + byte bits = smallFCD[lead >> 8]; + if (bits == 0) { + return false; + } + return ((bits >> ((lead >> 5) & 7)) & 1) != 0; + } + + /** Gets the FCD value from the regular normalization data. */ + public int getFCD16FromNormData(int c) { + int norm16 = getNorm16(c); + if (norm16 >= limitNoNo) { + if (norm16 >= MIN_NORMAL_MAYBE_YES) { + // combining mark + norm16 = getCCFromNormalYesOrMaybe(norm16); + return norm16 | (norm16 << 8); + } else if (norm16 >= minMaybeYes) { + return 0; + } else { // isDecompNoAlgorithmic(norm16) + int deltaTrailCC = norm16 & DELTA_TCCC_MASK; + if (deltaTrailCC <= DELTA_TCCC_1) { + return deltaTrailCC >> OFFSET_SHIFT; + } + // Maps to an isCompYesAndZeroCC. + c = mapAlgorithmic(c, norm16); + norm16 = getRawNorm16(c); + } + } + if (norm16 <= minYesNo || isHangulLVT(norm16)) { + // no decomposition or Hangul syllable, all zeros + return 0; + } + // c decomposes, get everything from the variable-length extra data + int mapping = norm16 >> OFFSET_SHIFT; + int firstUnit = extraData.charAt(mapping); + int fcd16 = firstUnit >> 8; // tccc + if ((firstUnit & MAPPING_HAS_CCC_LCCC_WORD) != 0) { + fcd16 |= extraData.charAt(mapping - 1) & 0xff00; // lccc + } + return fcd16; + } + + /** + * Gets the decomposition for one code point. + * + * @param c code point + * @return c's decomposition, if it has one; returns null if it does not have a + * decomposition + */ + public String getDecomposition(int c) { + int norm16; + if (c < minDecompNoCP || isMaybeOrNonZeroCC(norm16 = getNorm16(c))) { + // c does not decompose + return null; + } + int decomp = -1; + if (isDecompNoAlgorithmic(norm16)) { + // Maps to an isCompYesAndZeroCC. + decomp = c = mapAlgorithmic(c, norm16); + // The mapping might decompose further. + norm16 = getRawNorm16(c); + } + if (norm16 < minYesNo) { + if (decomp < 0) { + return null; + } else { + return UTF16.valueOf(decomp); + } + } else if (isHangulLV(norm16) || isHangulLVT(norm16)) { + // Hangul syllable: decompose algorithmically + StringBuilder buffer = new StringBuilder(); + Hangul.decompose(c, buffer); + return buffer.toString(); + } + // c decomposes, get everything from the variable-length extra data + int mapping = norm16 >> OFFSET_SHIFT; + int length = extraData.charAt(mapping++) & MAPPING_LENGTH_MASK; + return extraData.substring(mapping, mapping + length); + } + + // Fixed norm16 values. + public static final int MIN_YES_YES_WITH_CC = 0xfe02; + public static final int JAMO_VT = 0xfe00; + public static final int MIN_NORMAL_MAYBE_YES = 0xfc00; + public static final int JAMO_L = 2; // offset=1 hasCompBoundaryAfter=FALSE + public static final int INERT = 1; // offset=0 hasCompBoundaryAfter=TRUE + + // norm16 bit 0 is comp-boundary-after. + public static final int HAS_COMP_BOUNDARY_AFTER = 1; + public static final int OFFSET_SHIFT = 1; + + // For algorithmic one-way mappings, norm16 bits 2..1 indicate the + // tccc (0, 1, >1) for quick FCC boundary-after tests. + public static final int DELTA_TCCC_0 = 0; + public static final int DELTA_TCCC_1 = 2; + public static final int DELTA_TCCC_GT_1 = 4; + public static final int DELTA_TCCC_MASK = 6; + public static final int DELTA_SHIFT = 3; + + public static final int MAX_DELTA = 0x40; + + // Byte offsets from the start of the data, after the generic header. + public static final int IX_NORM_TRIE_OFFSET = 0; + public static final int IX_EXTRA_DATA_OFFSET = 1; + public static final int IX_SMALL_FCD_OFFSET = 2; + public static final int IX_RESERVED3_OFFSET = 3; + public static final int IX_TOTAL_SIZE = 7; + public static final int MIN_CCC_LCCC_CP = 0x300; + // Code point thresholds for quick check codes. + public static final int IX_MIN_DECOMP_NO_CP = 8; + public static final int IX_MIN_COMP_NO_MAYBE_CP = 9; + + // Norm16 value thresholds for quick check combinations and types of extra data. + + /** Mappings & compositions in [minYesNo..minYesNoMappingsOnly[. */ + public static final int IX_MIN_YES_NO = 10; + /** Mappings are comp-normalized. */ + public static final int IX_MIN_NO_NO = 11; + public static final int IX_LIMIT_NO_NO = 12; + public static final int IX_MIN_MAYBE_YES = 13; + + /** Mappings only in [minYesNoMappingsOnly..minNoNo[. */ + public static final int IX_MIN_YES_NO_MAPPINGS_ONLY = 14; + /** Mappings are not comp-normalized but have a comp boundary before. */ + public static final int IX_MIN_NO_NO_COMP_BOUNDARY_BEFORE = 15; + /** Mappings do not have a comp boundary before. */ + public static final int IX_MIN_NO_NO_COMP_NO_MAYBE_CC = 16; + /** Mappings to the empty string. */ + public static final int IX_MIN_NO_NO_EMPTY = 17; + + public static final int IX_MIN_LCCC_CP = 18; + public static final int IX_COUNT = 20; + + public static final int MAPPING_HAS_CCC_LCCC_WORD = 0x80; + public static final int MAPPING_HAS_RAW_MAPPING = 0x40; + // unused bit 0x20; + public static final int MAPPING_LENGTH_MASK = 0x1f; + + public static final int COMP_1_LAST_TUPLE = 0x8000; + public static final int COMP_1_TRIPLE = 1; + public static final int COMP_1_TRAIL_LIMIT = 0x3400; + public static final int COMP_1_TRAIL_MASK = 0x7ffe; + public static final int COMP_1_TRAIL_SHIFT = 9; // 10-1 for the "triple" bit + public static final int COMP_2_TRAIL_SHIFT = 6; + public static final int COMP_2_TRAIL_MASK = 0xffc0; + + // higher-level functionality ------------------------------------------ *** + + /** + * Decomposes s[src, limit[ and writes the result to dest. limit can be NULL if + * src is NUL-terminated. destLengthEstimate is the initial dest buffer capacity + * and can be -1. + */ + public void decompose(CharSequence s, int src, int limit, StringBuilder dest, int destLengthEstimate) { + if (destLengthEstimate < 0) { + destLengthEstimate = limit - src; + } + dest.setLength(0); + ReorderingBuffer buffer = new ReorderingBuffer(this, dest, destLengthEstimate); + decompose(s, src, limit, buffer); + } + + // Dual functionality: + // buffer!=NULL: normalize + // buffer==NULL: isNormalized/quickCheck/spanQuickCheckYes + public int decompose(CharSequence s, int src, int limit, ReorderingBuffer buffer) { + int minNoCP = minDecompNoCP; + + int prevSrc; + int c = 0; + int norm16 = 0; + + // only for quick check + int prevBoundary = src; + int prevCC = 0; + + for (;;) { + // count code units below the minimum or with irrelevant data for the quick + // check + for (prevSrc = src; src != limit;) { + if ((c = s.charAt(src)) < minNoCP || isMostDecompYesAndZeroCC(norm16 = normTrie.bmpGet(c))) { + ++src; + } else if (!UTF16Plus.isLeadSurrogate(c)) { + break; + } else { + char c2; + if ((src + 1) != limit && Character.isLowSurrogate(c2 = s.charAt(src + 1))) { + c = Character.toCodePoint((char) c, c2); + norm16 = normTrie.suppGet(c); + if (isMostDecompYesAndZeroCC(norm16)) { + src += 2; + } else { + break; + } + } else { + ++src; // unpaired lead surrogate: inert + } + } + } + // copy these code units all at once + if (src != prevSrc) { + if (buffer != null) { + buffer.flushAndAppendZeroCC(s, prevSrc, src); + } else { + prevCC = 0; + prevBoundary = src; + } + } + if (src == limit) { + break; + } + + // Check one above-minimum, relevant code point. + src += Character.charCount(c); + if (buffer != null) { + decompose(c, norm16, buffer); + } else { + if (isDecompYes(norm16)) { + int cc = getCCFromYesOrMaybe(norm16); + if (prevCC <= cc || cc == 0) { + prevCC = cc; + if (cc <= 1) { + prevBoundary = src; + } + continue; + } + } + return prevBoundary; // "no" or cc out of order + } + } + return src; + } + + public void decomposeAndAppend(CharSequence s, boolean doDecompose, ReorderingBuffer buffer) { + int limit = s.length(); + if (limit == 0) { + return; + } + if (doDecompose) { + decompose(s, 0, limit, buffer); + return; + } + // Just merge the strings at the boundary. + int c = Character.codePointAt(s, 0); + int src = 0; + int firstCC, prevCC, cc; + firstCC = prevCC = cc = getCC(getNorm16(c)); + while (cc != 0) { + prevCC = cc; + src += Character.charCount(c); + if (src >= limit) { + break; + } + c = Character.codePointAt(s, src); + cc = getCC(getNorm16(c)); + } + ; + buffer.append(s, 0, src, false, firstCC, prevCC); + buffer.append(s, src, limit); + } + + // Very similar to composeQuickCheck(): Make the same changes in both places if + // relevant. + // doCompose: normalize + // !doCompose: isNormalized (buffer must be empty and initialized) + public boolean compose(CharSequence s, int src, int limit, boolean onlyContiguous, boolean doCompose, + ReorderingBuffer buffer) { + int prevBoundary = src; + int minNoMaybeCP = minCompNoMaybeCP; + + for (;;) { + // Fast path: Scan over a sequence of characters below the minimum "no or maybe" + // code point, + // or with (compYes && ccc==0) properties. + int prevSrc; + int c = 0; + int norm16 = 0; + for (;;) { + if (src == limit) { + if (prevBoundary != limit && doCompose) { + buffer.append(s, prevBoundary, limit); + } + return true; + } + if ((c = s.charAt(src)) < minNoMaybeCP || isCompYesAndZeroCC(norm16 = normTrie.bmpGet(c))) { + ++src; + } else { + prevSrc = src++; + if (!UTF16Plus.isLeadSurrogate(c)) { + break; + } else { + char c2; + if (src != limit && Character.isLowSurrogate(c2 = s.charAt(src))) { + ++src; + c = Character.toCodePoint((char) c, c2); + norm16 = normTrie.suppGet(c); + if (!isCompYesAndZeroCC(norm16)) { + break; + } + } + } + } + } + // isCompYesAndZeroCC(norm16) is false, that is, norm16>=minNoNo. + // The current character is either a "noNo" (has a mapping) + // or a "maybeYes" (combines backward) + // or a "yesYes" with ccc!=0. + // It is not a Hangul syllable or Jamo L because those have "yes" properties. + + // Medium-fast path: Handle cases that do not require full decomposition and + // recomposition. + if (!isMaybeOrNonZeroCC(norm16)) { // minNoNo <= norm16 < minMaybeYes + if (!doCompose) { + return false; + } + // Fast path for mapping a character that is immediately surrounded by + // boundaries. + // In this case, we need not decompose around the current character. + if (isDecompNoAlgorithmic(norm16)) { + // Maps to a single isCompYesAndZeroCC character + // which also implies hasCompBoundaryBefore. + if (norm16HasCompBoundaryAfter(norm16, onlyContiguous) || hasCompBoundaryBefore(s, src, limit)) { + if (prevBoundary != prevSrc) { + buffer.append(s, prevBoundary, prevSrc); + } + buffer.append(mapAlgorithmic(c, norm16), 0); + prevBoundary = src; + continue; + } + } else if (norm16 < minNoNoCompBoundaryBefore) { + // The mapping is comp-normalized which also implies hasCompBoundaryBefore. + if (norm16HasCompBoundaryAfter(norm16, onlyContiguous) || hasCompBoundaryBefore(s, src, limit)) { + if (prevBoundary != prevSrc) { + buffer.append(s, prevBoundary, prevSrc); + } + int mapping = norm16 >> OFFSET_SHIFT; + int length = extraData.charAt(mapping++) & MAPPING_LENGTH_MASK; + buffer.append(extraData, mapping, mapping + length); + prevBoundary = src; + continue; + } + } else if (norm16 >= minNoNoEmpty) { + // The current character maps to nothing. + // Simply omit it from the output if there is a boundary before _or_ after it. + // The character itself implies no boundaries. + if (hasCompBoundaryBefore(s, src, limit) + || hasCompBoundaryAfter(s, prevBoundary, prevSrc, onlyContiguous)) { + if (prevBoundary != prevSrc) { + buffer.append(s, prevBoundary, prevSrc); + } + prevBoundary = src; + continue; + } + } + // Other "noNo" type, or need to examine more text around this character: + // Fall through to the slow path. + } else if (isJamoVT(norm16) && prevBoundary != prevSrc) { + char prev = s.charAt(prevSrc - 1); + if (c < Hangul.JAMO_T_BASE) { + // The current character is a Jamo Vowel, + // compose with previous Jamo L and following Jamo T. + char l = (char) (prev - Hangul.JAMO_L_BASE); + if (l < Hangul.JAMO_L_COUNT) { + if (!doCompose) { + return false; + } + int t; + if (src != limit && 0 < (t = (s.charAt(src) - Hangul.JAMO_T_BASE)) && t < Hangul.JAMO_T_COUNT) { + // The next character is a Jamo T. + ++src; + } else if (hasCompBoundaryBefore(s, src, limit)) { + // No Jamo T follows, not even via decomposition. + t = 0; + } else { + t = -1; + } + if (t >= 0) { + int syllable = Hangul.HANGUL_BASE + + (l * Hangul.JAMO_V_COUNT + (c - Hangul.JAMO_V_BASE)) * Hangul.JAMO_T_COUNT + t; + --prevSrc; // Replace the Jamo L as well. + if (prevBoundary != prevSrc) { + buffer.append(s, prevBoundary, prevSrc); + } + buffer.append((char) syllable); + prevBoundary = src; + continue; + } + // If we see L+V+x where x!=T then we drop to the slow path, + // decompose and recompose. + // This is to deal with NFKC finding normal L and V but a + // compatibility variant of a T. + // We need to either fully compose that combination here + // (which would complicate the code and may not work with strange custom data) + // or use the slow path. + } + } else if (Hangul.isHangulLV(prev)) { + // The current character is a Jamo Trailing consonant, + // compose with previous Hangul LV that does not contain a Jamo T. + if (!doCompose) { + return false; + } + int syllable = prev + c - Hangul.JAMO_T_BASE; + --prevSrc; // Replace the Hangul LV as well. + if (prevBoundary != prevSrc) { + buffer.append(s, prevBoundary, prevSrc); + } + buffer.append((char) syllable); + prevBoundary = src; + continue; + } + // No matching context, or may need to decompose surrounding text first: + // Fall through to the slow path. + } else if (norm16 > JAMO_VT) { // norm16 >= MIN_YES_YES_WITH_CC + // One or more combining marks that do not combine-back: + // Check for canonical order, copy unchanged if ok and + // if followed by a character with a boundary-before. + int cc = getCCFromNormalYesOrMaybe(norm16); // cc!=0 + if (onlyContiguous /* FCC */ && getPreviousTrailCC(s, prevBoundary, prevSrc) > cc) { + // Fails FCD test, need to decompose and contiguously recompose. + if (!doCompose) { + return false; + } + } else { + // If !onlyContiguous (not FCC), then we ignore the tccc of + // the previous character which passed the quick check "yes && ccc==0" test. + int n16; + for (;;) { + if (src == limit) { + if (doCompose) { + buffer.append(s, prevBoundary, limit); + } + return true; + } + int prevCC = cc; + c = Character.codePointAt(s, src); + n16 = normTrie.get(c); + if (n16 >= MIN_YES_YES_WITH_CC) { + cc = getCCFromNormalYesOrMaybe(n16); + if (prevCC > cc) { + if (!doCompose) { + return false; + } + break; + } + } else { + break; + } + src += Character.charCount(c); + } + // p is after the last in-order combining mark. + // If there is a boundary here, then we continue with no change. + if (norm16HasCompBoundaryBefore(n16)) { + if (isCompYesAndZeroCC(n16)) { + src += Character.charCount(c); + } + continue; + } + // Use the slow path. There is no boundary in [prevSrc, src[. + } + } + + // Slow path: Find the nearest boundaries around the current character, + // decompose and recompose. + if (prevBoundary != prevSrc && !norm16HasCompBoundaryBefore(norm16)) { + c = Character.codePointBefore(s, prevSrc); + norm16 = normTrie.get(c); + if (!norm16HasCompBoundaryAfter(norm16, onlyContiguous)) { + prevSrc -= Character.charCount(c); + } + } + if (doCompose && prevBoundary != prevSrc) { + buffer.append(s, prevBoundary, prevSrc); + } + int recomposeStartIndex = buffer.length(); + // We know there is not a boundary here. + decomposeShort(s, prevSrc, src, false /* !stopAtCompBoundary */, onlyContiguous, buffer); + // Decompose until the next boundary. + src = decomposeShort(s, src, limit, true /* stopAtCompBoundary */, onlyContiguous, buffer); + recompose(buffer, recomposeStartIndex, onlyContiguous); + if (!doCompose) { + if (!buffer.equals(s, prevSrc, src)) { + return false; + } + buffer.remove(); + } + prevBoundary = src; + } + } + + /** + * Very similar to compose(): Make the same changes in both places if relevant. + * doSpan: spanQuickCheckYes (ignore bit 0 of the return value) !doSpan: + * quickCheck + * + * @return bits 31..1: spanQuickCheckYes (==s.length() if "yes") and bit 0: set + * if "maybe"; otherwise, if the span length<s.length() then the + * quick check result is "no" + */ + public int composeQuickCheck(CharSequence s, int src, int limit, boolean onlyContiguous, boolean doSpan) { + int qcResult = 0; + int prevBoundary = src; + int minNoMaybeCP = minCompNoMaybeCP; + + for (;;) { + // Fast path: Scan over a sequence of characters below the minimum "no or maybe" + // code point, + // or with (compYes && ccc==0) properties. + int prevSrc; + int c = 0; + int norm16 = 0; + for (;;) { + if (src == limit) { + return (src << 1) | qcResult; // "yes" or "maybe" + } + if ((c = s.charAt(src)) < minNoMaybeCP || isCompYesAndZeroCC(norm16 = normTrie.bmpGet(c))) { + ++src; + } else { + prevSrc = src++; + if (!UTF16Plus.isLeadSurrogate(c)) { + break; + } else { + char c2; + if (src != limit && Character.isLowSurrogate(c2 = s.charAt(src))) { + ++src; + c = Character.toCodePoint((char) c, c2); + norm16 = normTrie.suppGet(c); + if (!isCompYesAndZeroCC(norm16)) { + break; + } + } + } + } + } + // isCompYesAndZeroCC(norm16) is false, that is, norm16>=minNoNo. + // The current character is either a "noNo" (has a mapping) + // or a "maybeYes" (combines backward) + // or a "yesYes" with ccc!=0. + // It is not a Hangul syllable or Jamo L because those have "yes" properties. + + int prevNorm16 = INERT; + if (prevBoundary != prevSrc) { + prevBoundary = prevSrc; + if (!norm16HasCompBoundaryBefore(norm16)) { + c = Character.codePointBefore(s, prevSrc); + int n16 = getNorm16(c); + if (!norm16HasCompBoundaryAfter(n16, onlyContiguous)) { + prevBoundary -= Character.charCount(c); + prevNorm16 = n16; + } + } + } + + if (isMaybeOrNonZeroCC(norm16)) { + int cc = getCCFromYesOrMaybe(norm16); + if (onlyContiguous /* FCC */ && cc != 0 && getTrailCCFromCompYesAndZeroCC(prevNorm16) > cc) { + // The [prevBoundary..prevSrc[ character + // passed the quick check "yes && ccc==0" test + // but is out of canonical order with the current combining mark. + } else { + // If !onlyContiguous (not FCC), then we ignore the tccc of + // the previous character which passed the quick check "yes && ccc==0" test. + for (;;) { + if (norm16 < MIN_YES_YES_WITH_CC) { + if (!doSpan) { + qcResult = 1; + } else { + return prevBoundary << 1; // spanYes does not care to know it's "maybe" + } + } + if (src == limit) { + return (src << 1) | qcResult; // "yes" or "maybe" + } + int prevCC = cc; + c = Character.codePointAt(s, src); + norm16 = getNorm16(c); + if (isMaybeOrNonZeroCC(norm16)) { + cc = getCCFromYesOrMaybe(norm16); + if (!(prevCC <= cc || cc == 0)) { + break; + } + } else { + break; + } + src += Character.charCount(c); + } + // src is after the last in-order combining mark. + if (isCompYesAndZeroCC(norm16)) { + prevBoundary = src; + src += Character.charCount(c); + continue; + } + } + } + return prevBoundary << 1; // "no" + } + } + + public void composeAndAppend(CharSequence s, boolean doCompose, boolean onlyContiguous, ReorderingBuffer buffer) { + int src = 0, limit = s.length(); + if (!buffer.isEmpty()) { + int firstStarterInSrc = findNextCompBoundary(s, 0, limit, onlyContiguous); + if (0 != firstStarterInSrc) { + int lastStarterInDest = findPreviousCompBoundary(buffer.getStringBuilder(), buffer.length(), + onlyContiguous); + StringBuilder middle = new StringBuilder( + (buffer.length() - lastStarterInDest) + firstStarterInSrc + 16); + middle.append(buffer.getStringBuilder(), lastStarterInDest, buffer.length()); + buffer.removeSuffix(buffer.length() - lastStarterInDest); + middle.append(s, 0, firstStarterInSrc); + compose(middle, 0, middle.length(), onlyContiguous, true, buffer); + src = firstStarterInSrc; + } + } + if (doCompose) { + compose(s, src, limit, onlyContiguous, true, buffer); + } else { + buffer.append(s, src, limit); + } + } + + // Dual functionality: + // buffer!=NULL: normalize + // buffer==NULL: isNormalized/quickCheck/spanQuickCheckYes + public int makeFCD(CharSequence s, int src, int limit, ReorderingBuffer buffer) { + // Note: In this function we use buffer->appendZeroCC() because we track + // the lead and trail combining classes here, rather than leaving it to + // the ReorderingBuffer. + // The exception is the call to decomposeShort() which uses the buffer + // in the normal way. + + // Tracks the last FCD-safe boundary, before lccc=0 or after properly-ordered + // tccc<=1. + // Similar to the prevBoundary in the compose() implementation. + int prevBoundary = src; + int prevSrc; + int c = 0; + int prevFCD16 = 0; + int fcd16 = 0; + + for (;;) { + // count code units with lccc==0 + for (prevSrc = src; src != limit;) { + if ((c = s.charAt(src)) < minLcccCP) { + prevFCD16 = ~c; + ++src; + } else if (!singleLeadMightHaveNonZeroFCD16(c)) { + prevFCD16 = 0; + ++src; + } else { + if (UTF16Plus.isLeadSurrogate(c)) { + char c2; + if ((src + 1) != limit && Character.isLowSurrogate(c2 = s.charAt(src + 1))) { + c = Character.toCodePoint((char) c, c2); + } + } + if ((fcd16 = getFCD16FromNormData(c)) <= 0xff) { + prevFCD16 = fcd16; + src += Character.charCount(c); + } else { + break; + } + } + } + // copy these code units all at once + if (src != prevSrc) { + if (src == limit) { + if (buffer != null) { + buffer.flushAndAppendZeroCC(s, prevSrc, src); + } + break; + } + prevBoundary = src; + // We know that the previous character's lccc==0. + if (prevFCD16 < 0) { + // Fetching the fcd16 value was deferred for this below-minLcccCP code point. + int prev = ~prevFCD16; + if (prev < minDecompNoCP) { + prevFCD16 = 0; + } else { + prevFCD16 = getFCD16FromNormData(prev); + if (prevFCD16 > 1) { + --prevBoundary; + } + } + } else { + int p = src - 1; + if (Character.isLowSurrogate(s.charAt(p)) && prevSrc < p + && Character.isHighSurrogate(s.charAt(p - 1))) { + --p; + // Need to fetch the previous character's FCD value because + // prevFCD16 was just for the trail surrogate code point. + prevFCD16 = getFCD16FromNormData(Character.toCodePoint(s.charAt(p), s.charAt(p + 1))); + // Still known to have lccc==0 because its lead surrogate unit had lccc==0. + } + if (prevFCD16 > 1) { + prevBoundary = p; + } + } + if (buffer != null) { + // The last lccc==0 character is excluded from the + // flush-and-append call in case it needs to be modified. + buffer.flushAndAppendZeroCC(s, prevSrc, prevBoundary); + buffer.append(s, prevBoundary, src); + } + // The start of the current character (c). + prevSrc = src; + } else if (src == limit) { + break; + } + + src += Character.charCount(c); + // The current character (c) at [prevSrc..src[ has a non-zero lead combining + // class. + // Check for proper order, and decompose locally if necessary. + if ((prevFCD16 & 0xff) <= (fcd16 >> 8)) { + // proper order: prev tccc <= current lccc + if ((fcd16 & 0xff) <= 1) { + prevBoundary = src; + } + if (buffer != null) { + buffer.appendZeroCC(c); + } + prevFCD16 = fcd16; + continue; + } else if (buffer == null) { + return prevBoundary; // quick check "no" + } else { + /* + * Back out the part of the source that we copied or appended already but is now + * going to be decomposed. prevSrc is set to after what was copied/appended. + */ + buffer.removeSuffix(prevSrc - prevBoundary); + /* + * Find the part of the source that needs to be decomposed, up to the next safe + * boundary. + */ + src = findNextFCDBoundary(s, src, limit); + /* + * The source text does not fulfill the conditions for FCD. Decompose and + * reorder a limited piece of the text. + */ + decomposeShort(s, prevBoundary, src, false, false, buffer); + prevBoundary = src; + prevFCD16 = 0; + } + } + return src; + } + + public boolean hasDecompBoundaryBefore(int c) { + return c < minLcccCP || (c <= 0xffff && !singleLeadMightHaveNonZeroFCD16(c)) + || norm16HasDecompBoundaryBefore(getNorm16(c)); + } + + public boolean norm16HasDecompBoundaryBefore(int norm16) { + if (norm16 < minNoNoCompNoMaybeCC) { + return true; + } + if (norm16 >= limitNoNo) { + return norm16 <= MIN_NORMAL_MAYBE_YES || norm16 == JAMO_VT; + } + // c decomposes, get everything from the variable-length extra data + int mapping = norm16 >> OFFSET_SHIFT; + int firstUnit = extraData.charAt(mapping); + // true if leadCC==0 (hasFCDBoundaryBefore()) + return (firstUnit & MAPPING_HAS_CCC_LCCC_WORD) == 0 || (extraData.charAt(mapping - 1) & 0xff00) == 0; + } + + public boolean hasDecompBoundaryAfter(int c) { + if (c < minDecompNoCP) { + return true; + } + if (c <= 0xffff && !singleLeadMightHaveNonZeroFCD16(c)) { + return true; + } + return norm16HasDecompBoundaryAfter(getNorm16(c)); + } + + public boolean norm16HasDecompBoundaryAfter(int norm16) { + if (norm16 <= minYesNo || isHangulLVT(norm16)) { + return true; + } + if (norm16 >= limitNoNo) { + if (isMaybeOrNonZeroCC(norm16)) { + return norm16 <= MIN_NORMAL_MAYBE_YES || norm16 == JAMO_VT; + } + // Maps to an isCompYesAndZeroCC. + return (norm16 & DELTA_TCCC_MASK) <= DELTA_TCCC_1; + } + // c decomposes, get everything from the variable-length extra data + int mapping = norm16 >> OFFSET_SHIFT; + int firstUnit = extraData.charAt(mapping); + // decomp after-boundary: same as hasFCDBoundaryAfter(), + // fcd16<=1 || trailCC==0 + if (firstUnit > 0x1ff) { + return false; // trailCC>1 + } + if (firstUnit <= 0xff) { + return true; // trailCC==0 + } + // if(trailCC==1) test leadCC==0, same as checking for before-boundary + // true if leadCC==0 (hasFCDBoundaryBefore()) + return (firstUnit & MAPPING_HAS_CCC_LCCC_WORD) == 0 || (extraData.charAt(mapping - 1) & 0xff00) == 0; + } + + public boolean isDecompInert(int c) { + return isDecompYesAndZeroCC(getNorm16(c)); + } + + public boolean hasCompBoundaryBefore(int c) { + return c < minCompNoMaybeCP || norm16HasCompBoundaryBefore(getNorm16(c)); + } + + public boolean hasCompBoundaryAfter(int c, boolean onlyContiguous) { + return norm16HasCompBoundaryAfter(getNorm16(c), onlyContiguous); + } + + private boolean isMaybe(int norm16) { + return minMaybeYes <= norm16 && norm16 <= JAMO_VT; + } + + private boolean isMaybeOrNonZeroCC(int norm16) { + return norm16 >= minMaybeYes; + } + + private static boolean isInert(int norm16) { + return norm16 == INERT; + } + + private static boolean isJamoVT(int norm16) { + return norm16 == JAMO_VT; + } + + private int hangulLVT() { + return minYesNoMappingsOnly | HAS_COMP_BOUNDARY_AFTER; + } + + private boolean isHangulLV(int norm16) { + return norm16 == minYesNo; + } + + private boolean isHangulLVT(int norm16) { + return norm16 == hangulLVT(); + } + + private boolean isCompYesAndZeroCC(int norm16) { + return norm16 < minNoNo; + } + + // UBool isCompYes(uint16_t norm16) const { + // return norm16>=MIN_YES_YES_WITH_CC || norm16= limitNoNo; + } + + // For use with isCompYes(). + // Perhaps the compiler can combine the two tests for MIN_YES_YES_WITH_CC. + // static uint8_t getCCFromYes(uint16_t norm16) { + // return norm16>=MIN_YES_YES_WITH_CC ? getCCFromNormalYesOrMaybe(norm16) : 0; + // } + private int getCCFromNoNo(int norm16) { + int mapping = norm16 >> OFFSET_SHIFT; + if ((extraData.charAt(mapping) & MAPPING_HAS_CCC_LCCC_WORD) != 0) { + return extraData.charAt(mapping - 1) & 0xff; + } else { + return 0; + } + } + + int getTrailCCFromCompYesAndZeroCC(int norm16) { + if (norm16 <= minYesNo) { + return 0; // yesYes and Hangul LV have ccc=tccc=0 + } else { + // For Hangul LVT we harmlessly fetch a firstUnit with tccc=0 here. + return extraData.charAt(norm16 >> OFFSET_SHIFT) >> 8; // tccc from yesNo + } + } + + // Requires algorithmic-NoNo. + private int mapAlgorithmic(int c, int norm16) { + return c + (norm16 >> DELTA_SHIFT) - centerNoNoDelta; + } + + // Requires minYesNo>OFFSET_SHIFT); + // } + + /** + * @return index into maybeYesCompositions, or -1 + */ + private int getCompositionsListForDecompYes(int norm16) { + if (norm16 < JAMO_L || MIN_NORMAL_MAYBE_YES <= norm16) { + return -1; + } else { + if ((norm16 -= minMaybeYes) < 0) { + // norm16> OFFSET_SHIFT; + } + } + + /** + * @return index into maybeYesCompositions + */ + private int getCompositionsListForComposite(int norm16) { + // A composite has both mapping & compositions list. + int list = ((MIN_NORMAL_MAYBE_YES - minMaybeYes) + norm16) >> OFFSET_SHIFT; + int firstUnit = maybeYesCompositions.charAt(list); + return list + // mapping in maybeYesCompositions + 1 + // +1 to skip the first unit with the mapping length + (firstUnit & MAPPING_LENGTH_MASK); // + mapping length + } + + // Decompose a short piece of text which is likely to contain characters that + // fail the quick check loop and/or where the quick check loop's overhead + // is unlikely to be amortized. + // Called by the compose() and makeFCD() implementations. + // Public in Java for collation implementation code. + private int decomposeShort(CharSequence s, int src, int limit, boolean stopAtCompBoundary, boolean onlyContiguous, + ReorderingBuffer buffer) { + while (src < limit) { + int c = Character.codePointAt(s, src); + if (stopAtCompBoundary && c < minCompNoMaybeCP) { + return src; + } + int norm16 = getNorm16(c); + if (stopAtCompBoundary && norm16HasCompBoundaryBefore(norm16)) { + return src; + } + src += Character.charCount(c); + decompose(c, norm16, buffer); + if (stopAtCompBoundary && norm16HasCompBoundaryAfter(norm16, onlyContiguous)) { + return src; + } + } + return src; + } + + private void decompose(int c, int norm16, ReorderingBuffer buffer) { + // get the decomposition and the lead and trail cc's + if (norm16 >= limitNoNo) { + if (isMaybeOrNonZeroCC(norm16)) { + buffer.append(c, getCCFromYesOrMaybe(norm16)); + return; + } + // Maps to an isCompYesAndZeroCC. + c = mapAlgorithmic(c, norm16); + norm16 = getRawNorm16(c); + } + if (norm16 < minYesNo) { + // c does not decompose + buffer.append(c, 0); + } else if (isHangulLV(norm16) || isHangulLVT(norm16)) { + // Hangul syllable: decompose algorithmically + Hangul.decompose(c, buffer); + } else { + // c decomposes, get everything from the variable-length extra data + int mapping = norm16 >> OFFSET_SHIFT; + int firstUnit = extraData.charAt(mapping); + int length = firstUnit & MAPPING_LENGTH_MASK; + int leadCC, trailCC; + trailCC = firstUnit >> 8; + if ((firstUnit & MAPPING_HAS_CCC_LCCC_WORD) != 0) { + leadCC = extraData.charAt(mapping - 1) >> 8; + } else { + leadCC = 0; + } + ++mapping; // skip over the firstUnit + buffer.append(extraData, mapping, mapping + length, true, leadCC, trailCC); + } + } + + /** + * Finds the recomposition result for a forward-combining "lead" character, + * specified with a pointer to its compositions list, and a backward-combining + * "trail" character. + * + *

+ * If the lead and trail characters combine, then this function returns the + * following "compositeAndFwd" value: + * + *

+	 * Bits 21..1  composite character
+	 * Bit      0  set if the composite is a forward-combining starter
+	 * 
+ * + * otherwise it returns -1. + * + *

+ * The compositions list has (trail, compositeAndFwd) pair entries, encoded as + * either pairs or triples of 16-bit units. The last entry has the high bit of + * its first unit set. + * + *

+ * The list is sorted by ascending trail characters (there are no duplicates). A + * linear search is used. + * + *

+ * See normalizer2impl.h for a more detailed description of the compositions + * list format. + */ + private static int combine(String compositions, int list, int trail) { + int key1, firstUnit; + if (trail < COMP_1_TRAIL_LIMIT) { + // trail character is 0..33FF + // result entry may have 2 or 3 units + key1 = (trail << 1); + while (key1 > (firstUnit = compositions.charAt(list))) { + list += 2 + (firstUnit & COMP_1_TRIPLE); + } + if (key1 == (firstUnit & COMP_1_TRAIL_MASK)) { + if ((firstUnit & COMP_1_TRIPLE) != 0) { + return (compositions.charAt(list + 1) << 16) | compositions.charAt(list + 2); + } else { + return compositions.charAt(list + 1); + } + } + } else { + // trail character is 3400..10FFFF + // result entry has 3 units + key1 = COMP_1_TRAIL_LIMIT + (((trail >> COMP_1_TRAIL_SHIFT)) & ~COMP_1_TRIPLE); + int key2 = (trail << COMP_2_TRAIL_SHIFT) & 0xffff; + int secondUnit; + for (;;) { + if (key1 > (firstUnit = compositions.charAt(list))) { + list += 2 + (firstUnit & COMP_1_TRIPLE); + } else if (key1 == (firstUnit & COMP_1_TRAIL_MASK)) { + if (key2 > (secondUnit = compositions.charAt(list + 1))) { + if ((firstUnit & COMP_1_LAST_TUPLE) != 0) { + break; + } else { + list += 3; + } + } else if (key2 == (secondUnit & COMP_2_TRAIL_MASK)) { + return ((secondUnit & ~COMP_2_TRAIL_MASK) << 16) | compositions.charAt(list + 2); + } else { + break; + } + } else { + break; + } + } + } + return -1; + } + + /* + * Recomposes the buffer text starting at recomposeStartIndex (which is in NFD - + * decomposed and canonically ordered), and truncates the buffer contents. + * + * Note that recomposition never lengthens the text: Any character consists of + * either one or two code units; a composition may contain at most one more code + * unit than the original starter, while the combining mark that is removed has + * at least one code unit. + */ + private void recompose(ReorderingBuffer buffer, int recomposeStartIndex, boolean onlyContiguous) { + StringBuilder sb = buffer.getStringBuilder(); + int p = recomposeStartIndex; + if (p == sb.length()) { + return; + } + + int starter, pRemove; + int compositionsList; + int c, compositeAndFwd; + int norm16; + int cc, prevCC; + boolean starterIsSupplementary; + + // Some of the following variables are not used until we have a + // forward-combining starter + // and are only initialized now to avoid compiler warnings. + compositionsList = -1; // used as indicator for whether we have a forward-combining starter + starter = -1; + starterIsSupplementary = false; + prevCC = 0; + + for (;;) { + c = sb.codePointAt(p); + p += Character.charCount(c); + norm16 = getNorm16(c); + cc = getCCFromYesOrMaybe(norm16); + if ( // this character combines backward and + isMaybe(norm16) && + // we have seen a starter that combines forward and + compositionsList >= 0 && + // the backward-combining character is not blocked + (prevCC < cc || prevCC == 0)) { + if (isJamoVT(norm16)) { + // c is a Jamo V/T, see if we can compose it with the previous character. + if (c < Hangul.JAMO_T_BASE) { + // c is a Jamo Vowel, compose with previous Jamo L and following Jamo T. + char prev = (char) (sb.charAt(starter) - Hangul.JAMO_L_BASE); + if (prev < Hangul.JAMO_L_COUNT) { + pRemove = p - 1; + char syllable = (char) (Hangul.HANGUL_BASE + + (prev * Hangul.JAMO_V_COUNT + (c - Hangul.JAMO_V_BASE)) * Hangul.JAMO_T_COUNT); + char t; + if (p != sb.length() + && (t = (char) (sb.charAt(p) - Hangul.JAMO_T_BASE)) < Hangul.JAMO_T_COUNT) { + ++p; + syllable += t; // The next character was a Jamo T. + } + sb.setCharAt(starter, syllable); + // remove the Jamo V/T + sb.delete(pRemove, p); + p = pRemove; + } + } + /* + * No "else" for Jamo T: Since the input is in NFD, there are no Hangul LV + * syllables that a Jamo T could combine with. All Jamo Ts are combined above + * when handling Jamo Vs. + */ + if (p == sb.length()) { + break; + } + compositionsList = -1; + continue; + } else if ((compositeAndFwd = combine(maybeYesCompositions, compositionsList, c)) >= 0) { + // The starter and the combining mark (c) do combine. + int composite = compositeAndFwd >> 1; + + // Remove the combining mark. + pRemove = p - Character.charCount(c); // pRemove & p: start & limit of the combining mark + sb.delete(pRemove, p); + p = pRemove; + // Replace the starter with the composite. + if (starterIsSupplementary) { + if (composite > 0xffff) { + // both are supplementary + sb.setCharAt(starter, UTF16.getLeadSurrogate(composite)); + sb.setCharAt(starter + 1, UTF16.getTrailSurrogate(composite)); + } else { + sb.setCharAt(starter, (char) c); + sb.deleteCharAt(starter + 1); + // The composite is shorter than the starter, + // move the intermediate characters forward one. + starterIsSupplementary = false; + --p; + } + } else if (composite > 0xffff) { + // The composite is longer than the starter, + // move the intermediate characters back one. + starterIsSupplementary = true; + sb.setCharAt(starter, UTF16.getLeadSurrogate(composite)); + sb.insert(starter + 1, UTF16.getTrailSurrogate(composite)); + ++p; + } else { + // both are on the BMP + sb.setCharAt(starter, (char) composite); + } + + // Keep prevCC because we removed the combining mark. + + if (p == sb.length()) { + break; + } + // Is the composite a starter that combines forward? + if ((compositeAndFwd & 1) != 0) { + compositionsList = getCompositionsListForComposite(getRawNorm16(composite)); + } else { + compositionsList = -1; + } + + // We combined; continue with looking for compositions. + continue; + } + } + + // no combination this time + prevCC = cc; + if (p == sb.length()) { + break; + } + + // If c did not combine, then check if it is a starter. + if (cc == 0) { + // Found a new starter. + if ((compositionsList = getCompositionsListForDecompYes(norm16)) >= 0) { + // It may combine with something, prepare for it. + if (c <= 0xffff) { + starterIsSupplementary = false; + starter = p - 1; + } else { + starterIsSupplementary = true; + starter = p - 2; + } + } + } else if (onlyContiguous) { + // FCC: no discontiguous compositions; any intervening character blocks. + compositionsList = -1; + } + } + buffer.flush(); + } + + /** + * Does c have a composition boundary before it? True if its decomposition + * begins with a character that has ccc=0 && NFC_QC=Yes (isCompYesAndZeroCC()). + * As a shortcut, this is true if c itself has ccc=0 && NFC_QC=Yes + * (isCompYesAndZeroCC()) so we need not decompose. + */ + private boolean hasCompBoundaryBefore(int c, int norm16) { + return c < minCompNoMaybeCP || norm16HasCompBoundaryBefore(norm16); + } + + private boolean norm16HasCompBoundaryBefore(int norm16) { + return norm16 < minNoNoCompNoMaybeCC || isAlgorithmicNoNo(norm16); + } + + private boolean hasCompBoundaryBefore(CharSequence s, int src, int limit) { + return src == limit || hasCompBoundaryBefore(Character.codePointAt(s, src)); + } + + private boolean norm16HasCompBoundaryAfter(int norm16, boolean onlyContiguous) { + return (norm16 & HAS_COMP_BOUNDARY_AFTER) != 0 && (!onlyContiguous || isTrailCC01ForCompBoundaryAfter(norm16)); + } + + private boolean hasCompBoundaryAfter(CharSequence s, int start, int p, boolean onlyContiguous) { + return start == p || hasCompBoundaryAfter(Character.codePointBefore(s, p), onlyContiguous); + } + + /** For FCC: Given norm16 HAS_COMP_BOUNDARY_AFTER, does it have tccc<=1? */ + private boolean isTrailCC01ForCompBoundaryAfter(int norm16) { + return isInert(norm16) || (isDecompNoAlgorithmic(norm16) ? (norm16 & DELTA_TCCC_MASK) <= DELTA_TCCC_1 + : extraData.charAt(norm16 >> OFFSET_SHIFT) <= 0x1ff); + } + + private int findPreviousCompBoundary(CharSequence s, int p, boolean onlyContiguous) { + while (p > 0) { + int c = Character.codePointBefore(s, p); + int norm16 = getNorm16(c); + if (norm16HasCompBoundaryAfter(norm16, onlyContiguous)) { + break; + } + p -= Character.charCount(c); + if (hasCompBoundaryBefore(c, norm16)) { + break; + } + } + return p; + } + + private int findNextCompBoundary(CharSequence s, int p, int limit, boolean onlyContiguous) { + while (p < limit) { + int c = Character.codePointAt(s, p); + int norm16 = normTrie.get(c); + if (hasCompBoundaryBefore(c, norm16)) { + break; + } + p += Character.charCount(c); + if (norm16HasCompBoundaryAfter(norm16, onlyContiguous)) { + break; + } + } + return p; + } + + private int findNextFCDBoundary(CharSequence s, int p, int limit) { + while (p < limit) { + int c = Character.codePointAt(s, p); + int norm16; + if (c < minLcccCP || norm16HasDecompBoundaryBefore(norm16 = getNorm16(c))) { + break; + } + p += Character.charCount(c); + if (norm16HasDecompBoundaryAfter(norm16)) { + break; + } + } + return p; + } + + /** + * Get the canonical decomposition sherman for ComposedCharIter + */ + public static int getDecompose(int chars[], String decomps[]) { + Normalizer2 impl = Normalizer2.getNFDInstance(); + + int length = 0; + int norm16 = 0; + int ch = -1; + int i = 0; + + while (++ch < 0x2fa1e) { // no cannoical above 0x3ffff + // TBD !!!! the hack code heres save us about 50ms for startup + // need a better solution/lookup + if (ch == 0x30ff) + ch = 0xf900; + else if (ch == 0x115bc) + ch = 0x1d15e; + else if (ch == 0x1d1c1) + ch = 0x2f800; + + String s = impl.getDecomposition(ch); + + if (s != null && i < chars.length) { + chars[i] = ch; + decomps[i++] = s; + } + } + return i; + } + + // ------------------------------------------------------ + // special method for Collation (RBTableBuilder.build()) + // ------------------------------------------------------ + private static boolean needSingleQuotation(char c) { + return (c >= 0x0009 && c <= 0x000D) || (c >= 0x0020 && c <= 0x002F) || (c >= 0x003A && c <= 0x0040) + || (c >= 0x005B && c <= 0x0060) || (c >= 0x007B && c <= 0x007E); + } + + public static String canonicalDecomposeWithSingleQuotation(String string) { + Normalizer2 impl = Normalizer2.getNFDInstance(); + char[] src = string.toCharArray(); + int srcIndex = 0; + int srcLimit = src.length; + char[] dest = new char[src.length * 3]; // MAX_BUF_SIZE_DECOMPOSE = 3 + int destIndex = 0; + int destLimit = dest.length; + + int prevSrc; + String norm; + int reorderStartIndex, length; + char c1, c2; + int cp; + int minNoMaybe = 0x00c0; + int cc, prevCC, trailCC; + char[] p; + int pStart; + + // initialize + reorderStartIndex = 0; + prevCC = 0; + norm = null; + cp = 0; + pStart = 0; + + cc = trailCC = -1; // initialize to bogus value + c1 = 0; + for (;;) { + prevSrc = srcIndex; + // quick check (1)less than minNoMaybe (2)no decomp (3)hangual + while (srcIndex != srcLimit && ((c1 = src[srcIndex]) < minNoMaybe + || (norm = impl.getDecomposition(cp = string.codePointAt(srcIndex))) == null + || (c1 >= '\uac00' && c1 <= '\ud7a3'))) { // Hangul Syllables + prevCC = 0; + srcIndex += (cp < 0x10000) ? 1 : 2; + } + + // copy these code units all at once + if (srcIndex != prevSrc) { + length = srcIndex - prevSrc; + if ((destIndex + length) <= destLimit) { + System.arraycopy(src, prevSrc, dest, destIndex, length); + } + + destIndex += length; + reorderStartIndex = destIndex; + } + + // end of source reached? + if (srcIndex == srcLimit) { + break; + } + + // cp already contains *src and norm32 is set for it, increment src + srcIndex += (cp < 0x10000) ? 1 : 2; + + if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) { + c2 = 0; + length = 1; + + if (Character.isHighSurrogate(c1) || Character.isLowSurrogate(c1)) { + norm = null; + } + } else { + length = 2; + c2 = src[srcIndex - 1]; + } + + // get the decomposition and the lead and trail cc's + if (norm == null) { + // cp does not decompose + cc = trailCC = UCharacter.getCombiningClass(cp); + p = null; + pStart = -1; + } else { + + pStart = 0; + p = norm.toCharArray(); + length = p.length; + int cpNum = norm.codePointCount(0, length); + cc = UCharacter.getCombiningClass(norm.codePointAt(0)); + trailCC = UCharacter.getCombiningClass(norm.codePointAt(cpNum - 1)); + if (length == 1) { + // fastpath a single code unit from decomposition + c1 = p[pStart]; + c2 = 0; + p = null; + pStart = -1; + } + } + + if ((destIndex + length * 3) >= destLimit) { // 2 SingleQuotations + // buffer overflow + char[] tmpBuf = new char[destLimit * 2]; + System.arraycopy(dest, 0, tmpBuf, 0, destIndex); + dest = tmpBuf; + destLimit = dest.length; + } + + // append the decomposition to the destination buffer, assume length>0 + { + int reorderSplit = destIndex; + if (p == null) { + // fastpath: single code point + if (needSingleQuotation(c1)) { + // if we need single quotation, no need to consider "prevCC" + // and it must NOT be a supplementary pair + dest[destIndex++] = '\''; + dest[destIndex++] = c1; + dest[destIndex++] = '\''; + trailCC = 0; + } else if (cc != 0 && cc < prevCC) { + // (c1, c2) is out of order with respect to the preceding + // text + destIndex += length; + trailCC = insertOrdered(dest, reorderStartIndex, reorderSplit, destIndex, c1, c2, cc); + } else { + // just append (c1, c2) + dest[destIndex++] = c1; + if (c2 != 0) { + dest[destIndex++] = c2; + } + } + } else { + // general: multiple code points (ordered by themselves) + // from decomposition + if (needSingleQuotation(p[pStart])) { + dest[destIndex++] = '\''; + dest[destIndex++] = p[pStart++]; + dest[destIndex++] = '\''; + length--; + do { + dest[destIndex++] = p[pStart++]; + } while (--length > 0); + } else if (cc != 0 && cc < prevCC) { + destIndex += length; + trailCC = mergeOrdered(dest, reorderStartIndex, reorderSplit, p, pStart, pStart + length); + } else { + // just append the decomposition + do { + dest[destIndex++] = p[pStart++]; + } while (--length > 0); + } + } + } + prevCC = trailCC; + if (prevCC == 0) { + reorderStartIndex = destIndex; + } + } + + return new String(dest, 0, destIndex); + } + + /** + * simpler, single-character version of mergeOrdered() - bubble-insert one + * single code point into the preceding string which is already canonically + * ordered (c, c2) may or may not yet have been inserted at src[current]..src[p] + * + * it must be p=current+lengthof(c, c2) i.e. p=current+(c2==0 ? 1 : 2) + * + * before: src[start]..src[current] is already ordered, and src[current]..src[p] + * may or may not hold (c, c2) but must be exactly the same length as (c, c2) + * after: src[start]..src[p] is ordered + * + * @return the trailing combining class + */ + private static int/* unsigned byte */ insertOrdered(char[] source, int start, int current, int p, char c1, char c2, + int/* unsigned byte */ cc) { + int back, preBack; + int r; + int prevCC, trailCC = cc; + + if (start < current && cc != 0) { + // search for the insertion point where cc>=prevCC + preBack = back = current; + + PrevArgs prevArgs = new PrevArgs(); + prevArgs.current = current; + prevArgs.start = start; + prevArgs.src = source; + prevArgs.c1 = c1; + prevArgs.c2 = c2; + + // get the prevCC + prevCC = getPrevCC(prevArgs); + preBack = prevArgs.current; + + if (cc < prevCC) { + // this will be the last code point, so keep its cc + trailCC = prevCC; + back = preBack; + while (start < preBack) { + prevCC = getPrevCC(prevArgs); + preBack = prevArgs.current; + if (cc >= prevCC) { + break; + } + back = preBack; + } + + // this is where we are right now with all these indicies: + // [start]..[pPreBack] 0..? code points that we can ignore + // [pPreBack]..[pBack] 0..1 code points with prevCC<=cc + // [pBack]..[current] 0..n code points with >cc, move up to insert (c, c2) + // [current]..[p] 1 code point (c, c2) with cc + + // move the code units in between up + r = p; + do { + source[--r] = source[--current]; + } while (back != current); + } + } + + // insert (c1, c2) + source[current] = c1; + if (c2 != 0) { + source[(current + 1)] = c2; + } + + // we know the cc of the last code point + return trailCC; + } + + /** + * merge two UTF-16 string parts together to canonically order (order by + * combining classes) their concatenation + * + * the two strings may already be adjacent, so that the merging is done in-place + * if the two strings are not adjacent, then the buffer holding the first one + * must be large enough the second string may or may not be ordered in itself + * + * before: [start]..[current] is already ordered, and [next]..[limit] may be + * ordered in itself, but is not in relation to [start..current[ after: + * [start..current+(limit-next)[ is ordered + * + * the algorithm is a simple bubble-sort that takes the characters from + * src[next++] and inserts them in correct combining class order into the + * preceding part of the string + * + * since this function is called much less often than the single-code point + * insertOrdered(), it just uses that for easier maintenance + * + * @return the trailing combining class + */ + private static int /* unsigned byte */ mergeOrdered(char[] source, int start, int current, char[] data, int next, + int limit) { + int r; + int /* unsigned byte */ cc, trailCC = 0; + boolean adjacent; + + adjacent = current == next; + NextCCArgs ncArgs = new NextCCArgs(); + ncArgs.source = data; + ncArgs.next = next; + ncArgs.limit = limit; + + if (start != current) { + + while (ncArgs.next < ncArgs.limit) { + cc = getNextCC(ncArgs); + if (cc == 0) { + // does not bubble back + trailCC = 0; + if (adjacent) { + current = ncArgs.next; + } else { + data[current++] = ncArgs.c1; + if (ncArgs.c2 != 0) { + data[current++] = ncArgs.c2; + } + } + break; + } else { + r = current + (ncArgs.c2 == 0 ? 1 : 2); + trailCC = insertOrdered(source, start, current, r, ncArgs.c1, ncArgs.c2, cc); + current = r; + } + } + } + + if (ncArgs.next == ncArgs.limit) { + // we know the cc of the last code point + return trailCC; + } else { + if (!adjacent) { + // copy the second string part + do { + source[current++] = data[ncArgs.next++]; + } while (ncArgs.next != ncArgs.limit); + ncArgs.limit = current; + } + PrevArgs prevArgs = new PrevArgs(); + prevArgs.src = data; + prevArgs.start = start; + prevArgs.current = ncArgs.limit; + return getPrevCC(prevArgs); + } + + } + + private static final class PrevArgs { + char[] src; + int start; + int current; + char c1; + char c2; + } + + private static final class NextCCArgs { + char[] source; + int next; + int limit; + char c1; + char c2; + } + + private static int /* unsigned byte */ getNextCC(NextCCArgs args) { + args.c1 = args.source[args.next++]; + args.c2 = 0; + + if (UTF16.isTrailSurrogate(args.c1)) { + /* unpaired second surrogate */ + return 0; + } else if (!UTF16.isLeadSurrogate(args.c1)) { + return UCharacter.getCombiningClass(args.c1); + } else if (args.next != args.limit && UTF16.isTrailSurrogate(args.c2 = args.source[args.next])) { + ++args.next; + return UCharacter.getCombiningClass(Character.toCodePoint(args.c1, args.c2)); + } else { + /* unpaired first surrogate */ + args.c2 = 0; + return 0; + } + } + + private static int /* unsigned */ getPrevCC(PrevArgs args) { + args.c1 = args.src[--args.current]; + args.c2 = 0; + + if (args.c1 < MIN_CCC_LCCC_CP) { + return 0; + } else if (UTF16.isLeadSurrogate(args.c1)) { + /* unpaired first surrogate */ + return 0; + } else if (!UTF16.isTrailSurrogate(args.c1)) { + return UCharacter.getCombiningClass(args.c1); + } else if (args.current != args.start && UTF16.isLeadSurrogate(args.c2 = args.src[args.current - 1])) { + --args.current; + return UCharacter.getCombiningClass(Character.toCodePoint(args.c2, args.c1)); + } else { + /* unpaired second surrogate */ + args.c2 = 0; + return 0; + } + } + + private int getPreviousTrailCC(CharSequence s, int start, int p) { + if (start == p) { + return 0; + } + return getFCD16(Character.codePointBefore(s, p)); + } + + private VersionInfo dataVersion; + + // BMP code point thresholds for quick check loops looking at single UTF-16 code + // units. + private int minDecompNoCP; + private int minCompNoMaybeCP; + private int minLcccCP; + + // Norm16 value thresholds for quick check combinations and types of extra data. + private int minYesNo; + private int minYesNoMappingsOnly; + private int minNoNo; + private int minNoNoCompBoundaryBefore; + private int minNoNoCompNoMaybeCC; + private int minNoNoEmpty; + private int limitNoNo; + private int centerNoNoDelta; + private int minMaybeYes; + + private CodePointTrie.Fast16 normTrie; + private String maybeYesCompositions; + private String extraData; // mappings and/or compositions for yesYes, yesNo & noNo characters + private byte[] smallFCD; // [0x100] one bit per 32 BMP code points, set if any FCD!=0 +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/Punycode.java b/src/main/java/jdk_internal/bidi/icu/impl/Punycode.java new file mode 100755 index 00000000..c6491b0c --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/Punycode.java @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + ******************************************************************************* + * Copyright (C) 2003-2004, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ +// +// CHANGELOG +// 2005-05-19 Edward Wang +// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/text/Punycode.java +// - move from package com.ibm.icu.text to package sun.net.idn +// - use ParseException instead of StringPrepParseException +// 2007-08-14 Martin Buchholz +// - remove redundant casts +// +package jdk_internal.bidi.icu.impl; + +import java.text.ParseException; + +import jdk_internal.bidi.icu.lang.UCharacter; +import jdk_internal.bidi.icu.text.UTF16; + +/** + * Ported code from ICU punycode.c + * + * @author ram + */ + +/* Package Private class */ +public final class Punycode { + + /* Punycode parameters for Bootstring */ + private static final int BASE = 36; + private static final int TMIN = 1; + private static final int TMAX = 26; + private static final int SKEW = 38; + private static final int DAMP = 700; + private static final int INITIAL_BIAS = 72; + private static final int INITIAL_N = 0x80; + + /* "Basic" Unicode/ASCII code points */ + private static final int HYPHEN = 0x2d; + private static final int DELIMITER = HYPHEN; + + private static final int ZERO = 0x30; + private static final int NINE = 0x39; + + private static final int SMALL_A = 0x61; + private static final int SMALL_Z = 0x7a; + + private static final int CAPITAL_A = 0x41; + private static final int CAPITAL_Z = 0x5a; + + // TODO: eliminate the 256 limitation + private static final int MAX_CP_COUNT = 256; + + private static final int UINT_MAGIC = 0x80000000; + private static final long ULONG_MAGIC = 0x8000000000000000L; + + private static int adaptBias(int delta, int length, boolean firstTime) { + if (firstTime) { + delta /= DAMP; + } else { + delta /= 2; + } + delta += delta / length; + + int count = 0; + for (; delta > ((BASE - TMIN) * TMAX) / 2; count += BASE) { + delta /= (BASE - TMIN); + } + + return count + (((BASE - TMIN + 1) * delta) / (delta + SKEW)); + } + + /** + * basicToDigit[] contains the numeric value of a basic code point (for use in + * representing integers) in the range 0 to BASE-1, or -1 if b is does not + * represent a value. + */ + static final int[] basicToDigit = new int[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, + -1, -1, -1, -1, -1, + + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, + -1, -1, -1, + + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, + -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1 }; + + private static char asciiCaseMap(char b, boolean uppercase) { + if (uppercase) { + if (SMALL_A <= b && b <= SMALL_Z) { + b -= (SMALL_A - CAPITAL_A); + } + } else { + if (CAPITAL_A <= b && b <= CAPITAL_Z) { + b += (SMALL_A - CAPITAL_A); + } + } + return b; + } + + /** + * digitToBasic() returns the basic code point whose value (when used for + * representing integers) is d, which must be in the range 0 to BASE-1. The + * lowercase form is used unless the uppercase flag is nonzero, in which case + * the uppercase form is used. + */ + private static char digitToBasic(int digit, boolean uppercase) { + /* 0..25 map to ASCII a..z or A..Z */ + /* 26..35 map to ASCII 0..9 */ + if (digit < 26) { + if (uppercase) { + return (char) (CAPITAL_A + digit); + } else { + return (char) (SMALL_A + digit); + } + } else { + return (char) ((ZERO - 26) + digit); + } + } + + /** + * Converts Unicode to Punycode. The input string must not contain single, + * unpaired surrogates. The output will be represented as an array of ASCII code + * points. + * + * @param src + * @param caseFlags + * @return + * @throws ParseException + */ + public static StringBuffer encode(StringBuffer src, boolean[] caseFlags) throws ParseException { + + int[] cpBuffer = new int[MAX_CP_COUNT]; + int n, delta, handledCPCount, basicLength, destLength, bias, j, m, q, k, t, srcCPCount; + char c, c2; + int srcLength = src.length(); + int destCapacity = MAX_CP_COUNT; + char[] dest = new char[destCapacity]; + StringBuffer result = new StringBuffer(); + /* + * Handle the basic code points and convert extended ones to UTF-32 in cpBuffer + * (caseFlag in sign bit): + */ + srcCPCount = destLength = 0; + + for (j = 0; j < srcLength; ++j) { + if (srcCPCount == MAX_CP_COUNT) { + /* too many input code points */ + throw new ParseException("Too many input code points", -1); + } + c = src.charAt(j); + if (isBasic(c)) { + if (destLength < destCapacity) { + cpBuffer[srcCPCount++] = 0; + dest[destLength] = caseFlags != null ? asciiCaseMap(c, caseFlags[j]) : c; + } + ++destLength; + } else { + n = ((caseFlags != null && caseFlags[j]) ? 1 : 0) << 31L; + if (!UTF16.isSurrogate(c)) { + n |= c; + } else if (UTF16.isLeadSurrogate(c) && (j + 1) < srcLength + && UTF16.isTrailSurrogate(c2 = src.charAt(j + 1))) { + ++j; + + n |= UCharacter.getCodePoint(c, c2); + } else { + /* error: unmatched surrogate */ + throw new ParseException("Illegal char found", -1); + } + cpBuffer[srcCPCount++] = n; + } + } + + /* Finish the basic string - if it is not empty - with a delimiter. */ + basicLength = destLength; + if (basicLength > 0) { + if (destLength < destCapacity) { + dest[destLength] = DELIMITER; + } + ++destLength; + } + + /* + * handledCPCount is the number of code points that have been handled + * basicLength is the number of basic code points destLength is the number of + * chars that have been output + */ + + /* Initialize the state: */ + n = INITIAL_N; + delta = 0; + bias = INITIAL_BIAS; + + /* Main encoding loop: */ + for (handledCPCount = basicLength; handledCPCount < srcCPCount; /* no op */) { + /* + * All non-basic code points < n have been handled already. Find the next larger + * one: + */ + for (m = 0x7fffffff, j = 0; j < srcCPCount; ++j) { + q = cpBuffer[j] & 0x7fffffff; /* remove case flag from the sign bit */ + if (n <= q && q < m) { + m = q; + } + } + + /* + * Increase delta enough to advance the decoder's state to , but + * guard against overflow: + */ + if (m - n > (0x7fffffff - MAX_CP_COUNT - delta) / (handledCPCount + 1)) { + throw new RuntimeException("Internal program error"); + } + delta += (m - n) * (handledCPCount + 1); + n = m; + + /* Encode a sequence of same code points n */ + for (j = 0; j < srcCPCount; ++j) { + q = cpBuffer[j] & 0x7fffffff; /* remove case flag from the sign bit */ + if (q < n) { + ++delta; + } else if (q == n) { + /* Represent delta as a generalized variable-length integer: */ + for (q = delta, k = BASE; /* no condition */; k += BASE) { + + /** + * RAM: comment out the old code for conformance with + * draft-ietf-idn-punycode-03.txt + * + * t=k-bias; if(tTMAX) { t=TMAX; } + */ + + t = k - bias; + if (t < TMIN) { + t = TMIN; + } else if (k >= (bias + TMAX)) { + t = TMAX; + } + + if (q < t) { + break; + } + + if (destLength < destCapacity) { + dest[destLength++] = digitToBasic(t + (q - t) % (BASE - t), false); + } + q = (q - t) / (BASE - t); + } + + if (destLength < destCapacity) { + dest[destLength++] = digitToBasic(q, (cpBuffer[j] < 0)); + } + bias = adaptBias(delta, handledCPCount + 1, (handledCPCount == basicLength)); + delta = 0; + ++handledCPCount; + } + } + + ++delta; + ++n; + } + + return result.append(dest, 0, destLength); + } + + private static boolean isBasic(int ch) { + return (ch < INITIAL_N); + } + + private static boolean isBasicUpperCase(int ch) { + return (CAPITAL_A <= ch && ch <= CAPITAL_Z); + } + + private static boolean isSurrogate(int ch) { + return (((ch) & 0xfffff800) == 0xd800); + } + + /** + * Converts Punycode to Unicode. The Unicode string will be at most as long as + * the Punycode string. + * + * @param src + * @param caseFlags + * @return + * @throws ParseException + */ + public static StringBuffer decode(StringBuffer src, boolean[] caseFlags) throws ParseException { + int srcLength = src.length(); + StringBuffer result = new StringBuffer(); + int n, destLength, i, bias, basicLength, j, in, oldi, w, k, digit, t, destCPCount, firstSupplementaryIndex, + cpLength; + char b; + int destCapacity = MAX_CP_COUNT; + char[] dest = new char[destCapacity]; + + /* + * Handle the basic code points: Let basicLength be the number of input code + * points before the last delimiter, or 0 if there is none, then copy the first + * basicLength code points to the output. + * + * The two following loops iterate backward. + */ + for (j = srcLength; j > 0;) { + if (src.charAt(--j) == DELIMITER) { + break; + } + } + destLength = basicLength = destCPCount = j; + + while (j > 0) { + b = src.charAt(--j); + if (!isBasic(b)) { + throw new ParseException("Illegal char found", -1); + } + + if (j < destCapacity) { + dest[j] = b; + + if (caseFlags != null) { + caseFlags[j] = isBasicUpperCase(b); + } + } + } + + /* Initialize the state: */ + n = INITIAL_N; + i = 0; + bias = INITIAL_BIAS; + firstSupplementaryIndex = 1000000000; + + /* + * Main decoding loop: Start just after the last delimiter if any basic code + * points were copied; start at the beginning otherwise. + */ + for (in = basicLength > 0 ? basicLength + 1 : 0; in < srcLength; /* no op */) { + /* + * in is the index of the next character to be consumed, and destCPCount is the + * number of code points in the output array. + * + * Decode a generalized variable-length integer into delta, which gets added to + * i. The overflow checking is easier if we increase i as we go, then subtract + * off its starting value at the end to obtain delta. + */ + for (oldi = i, w = 1, k = BASE; /* no condition */; k += BASE) { + if (in >= srcLength) { + throw new ParseException("Illegal char found", -1); + } + + digit = basicToDigit[(byte) src.charAt(in++)]; + if (digit < 0) { + throw new ParseException("Invalid char found", -1); + } + if (digit > (0x7fffffff - i) / w) { + /* integer overflow */ + throw new ParseException("Illegal char found", -1); + } + + i += digit * w; + t = k - bias; + if (t < TMIN) { + t = TMIN; + } else if (k >= (bias + TMAX)) { + t = TMAX; + } + if (digit < t) { + break; + } + + if (w > 0x7fffffff / (BASE - t)) { + /* integer overflow */ + throw new ParseException("Illegal char found", -1); + } + w *= BASE - t; + } + + /* + * Modification from sample code: Increments destCPCount here, where needed + * instead of in for() loop tail. + */ + ++destCPCount; + bias = adaptBias(i - oldi, destCPCount, (oldi == 0)); + + /* + * i was supposed to wrap around from (incremented) destCPCount to 0, + * incrementing n each time, so we'll fix that now: + */ + if (i / destCPCount > (0x7fffffff - n)) { + /* integer overflow */ + throw new ParseException("Illegal char found", -1); + } + + n += i / destCPCount; + i %= destCPCount; + /* not needed for Punycode: */ + /* if (decode_digit(n) <= BASE) return punycode_invalid_input; */ + + if (n > 0x10ffff || isSurrogate(n)) { + /* Unicode code point overflow */ + throw new ParseException("Illegal char found", -1); + } + + /* Insert n at position i of the output: */ + cpLength = UTF16.getCharCount(n); + if ((destLength + cpLength) < destCapacity) { + int codeUnitIndex; + + /* + * Handle indexes when supplementary code points are present. + * + * In almost all cases, there will be only BMP code points before i and even in + * the entire string. This is handled with the same efficiency as with UTF-32. + * + * Only the rare cases with supplementary code points are handled more slowly - + * but not too bad since this is an insertion anyway. + */ + if (i <= firstSupplementaryIndex) { + codeUnitIndex = i; + if (cpLength > 1) { + firstSupplementaryIndex = codeUnitIndex; + } else { + ++firstSupplementaryIndex; + } + } else { + codeUnitIndex = firstSupplementaryIndex; + codeUnitIndex = UTF16.moveCodePointOffset(dest, 0, destLength, codeUnitIndex, i - codeUnitIndex); + } + + /* use the UChar index codeUnitIndex instead of the code point index i */ + if (codeUnitIndex < destLength) { + System.arraycopy(dest, codeUnitIndex, dest, codeUnitIndex + cpLength, (destLength - codeUnitIndex)); + if (caseFlags != null) { + System.arraycopy(caseFlags, codeUnitIndex, caseFlags, codeUnitIndex + cpLength, + destLength - codeUnitIndex); + } + } + if (cpLength == 1) { + /* BMP, insert one code unit */ + dest[codeUnitIndex] = (char) n; + } else { + /* supplementary character, insert two code units */ + dest[codeUnitIndex] = UTF16.getLeadSurrogate(n); + dest[codeUnitIndex + 1] = UTF16.getTrailSurrogate(n); + } + if (caseFlags != null) { + /* Case of last character determines uppercase flag: */ + caseFlags[codeUnitIndex] = isBasicUpperCase(src.charAt(in - 1)); + if (cpLength == 2) { + caseFlags[codeUnitIndex + 1] = false; + } + } + } + destLength += cpLength; + ++i; + } + result.append(dest, 0, destLength); + return result; + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/ReplaceableUCharacterIterator.java b/src/main/java/jdk_internal/bidi/icu/impl/ReplaceableUCharacterIterator.java new file mode 100755 index 00000000..3e090726 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/ReplaceableUCharacterIterator.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.impl; + +import jdk_internal.bidi.icu.text.Replaceable; +import jdk_internal.bidi.icu.text.ReplaceableString; +import jdk_internal.bidi.icu.text.UCharacterIterator; + +/** + * DLF docs must define behavior when Replaceable is mutated underneath the + * iterator. + * + * This and ICUCharacterIterator share some code, maybe they should share an + * implementation, or the common state and implementation should be moved up + * into UCharacterIterator. + * + * What are first, last, and getBeginIndex doing here?!?!?! + */ +public class ReplaceableUCharacterIterator extends UCharacterIterator { + + // public constructor ------------------------------------------------------ + + /** + * Public constructor + * + * @param str text which the iterator will be based on + */ + public ReplaceableUCharacterIterator(String str) { + if (str == null) { + throw new IllegalArgumentException(); + } + this.replaceable = new ReplaceableString(str); + this.currentIndex = 0; + } + + /** + * Public constructor + * + * @param buf buffer of text on which the iterator will be based + */ + public ReplaceableUCharacterIterator(StringBuffer buf) { + if (buf == null) { + throw new IllegalArgumentException(); + } + this.replaceable = new ReplaceableString(buf); + this.currentIndex = 0; + } + + // public methods ---------------------------------------------------------- + + /** + * Creates a copy of this iterator, does not clone the underlying + * Replaceableobject + * + * @return copy of this iterator + */ + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + return null; // never invoked + } + } + + /** + * Returns the current UTF16 character. + * + * @return current UTF16 character + */ + public int current() { + if (currentIndex < replaceable.length()) { + return replaceable.charAt(currentIndex); + } + return DONE; + } + + /** + * Returns the length of the text + * + * @return length of the text + */ + public int getLength() { + return replaceable.length(); + } + + /** + * Gets the current currentIndex in text. + * + * @return current currentIndex in text. + */ + public int getIndex() { + return currentIndex; + } + + /** + * Returns next UTF16 character and increments the iterator's currentIndex by 1. + * If the resulting currentIndex is greater or equal to the text length, the + * currentIndex is reset to the text length and a value of DONECODEPOINT is + * returned. + * + * @return next UTF16 character in text or DONE if the new currentIndex is off + * the end of the text range. + */ + public int next() { + if (currentIndex < replaceable.length()) { + return replaceable.charAt(currentIndex++); + } + return DONE; + } + + /** + * Returns previous UTF16 character and decrements the iterator's currentIndex + * by 1. If the resulting currentIndex is less than 0, the currentIndex is reset + * to 0 and a value of DONECODEPOINT is returned. + * + * @return next UTF16 character in text or DONE if the new currentIndex is off + * the start of the text range. + */ + public int previous() { + if (currentIndex > 0) { + return replaceable.charAt(--currentIndex); + } + return DONE; + } + + /** + * Sets the currentIndex to the specified currentIndex in the text and returns + * that single UTF16 character at currentIndex. This assumes the text is stored + * as 16-bit code units. + * + * @param currentIndex the currentIndex within the text. + * @exception IllegalArgumentException is thrown if an invalid currentIndex is + * supplied. i.e. currentIndex is out of + * bounds. + */ + public void setIndex(int currentIndex) { + if (currentIndex < 0 || currentIndex > replaceable.length()) { + throw new IllegalArgumentException(); + } + this.currentIndex = currentIndex; + } + + public int getText(char[] fillIn, int offset) { + int length = replaceable.length(); + if (offset < 0 || offset + length > fillIn.length) { + throw new IndexOutOfBoundsException(Integer.toString(length)); + } + replaceable.getChars(0, length, fillIn, offset); + return length; + } + + // private data members ---------------------------------------------------- + + /** + * Replaceable object + */ + private Replaceable replaceable; + /** + * Current currentIndex + */ + private int currentIndex; + +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/StringPrepDataReader.java b/src/main/java/jdk_internal/bidi/icu/impl/StringPrepDataReader.java new file mode 100755 index 00000000..98aafc74 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/StringPrepDataReader.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* +/* + ****************************************************************************** + * Copyright (C) 2003, International Business Machines Corporation and * + * others. All Rights Reserved. * + ****************************************************************************** + * + * Created on May 2, 2003 + * + * To change the template for this generated file go to + * Window>Preferences>Java>Code Generation>Code and Comments + */ +// CHANGELOG +// 2005-05-19 Edward Wang +// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/impl/StringPrepDataReader.java +// - move from package com.ibm.icu.impl to package sun.net.idn +// +package jdk_internal.bidi.icu.impl; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * @author ram + * + * To change the template for this generated type comment go to + * Window>Preferences>Java>Code Generation>Code and Comments + */ +public final class StringPrepDataReader implements ICUBinary.Authenticate { + + /** + *

+ * private constructor. + *

+ * + * @param inputStream ICU uprop.dat file input stream + * @exception IOException throw if data file fails authentication + * @draft 2.1 + */ + public StringPrepDataReader(InputStream inputStream) throws IOException { + + unicodeVersion = ICUBinary.readHeader(inputStream, DATA_FORMAT_ID, this); + + dataInputStream = new DataInputStream(inputStream); + + } + + public void read(byte[] idnaBytes, char[] mappingTable) throws IOException { + + // Read the bytes that make up the idnaTrie + dataInputStream.read(idnaBytes); + + // Read the extra data + for (int i = 0; i < mappingTable.length; i++) { + mappingTable[i] = dataInputStream.readChar(); + } + } + + public byte[] getDataFormatVersion() { + return DATA_FORMAT_VERSION; + } + + public boolean isDataVersionAcceptable(byte version[]) { + return version[0] == DATA_FORMAT_VERSION[0] && version[2] == DATA_FORMAT_VERSION[2] + && version[3] == DATA_FORMAT_VERSION[3]; + } + + public int[] readIndexes(int length) throws IOException { + int[] indexes = new int[length]; + // Read the indexes + for (int i = 0; i < length; i++) { + indexes[i] = dataInputStream.readInt(); + } + return indexes; + } + + public byte[] getUnicodeVersion() { + return unicodeVersion; + } + // private data members ------------------------------------------------- + + /** + * ICU data file input stream + */ + private DataInputStream dataInputStream; + private byte[] unicodeVersion; + /** + * File format version that this class understands. No guarantees are made if a + * older version is used see store.c of gennorm for more information and values + */ + /// * dataFormat="SPRP" 0x53, 0x50, 0x52, 0x50 */ + private static final byte DATA_FORMAT_ID[] = { (byte) 0x53, (byte) 0x50, (byte) 0x52, (byte) 0x50 }; + private static final byte DATA_FORMAT_VERSION[] = { (byte) 0x3, (byte) 0x2, (byte) 0x5, (byte) 0x2 }; + +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/Trie.java b/src/main/java/jdk_internal/bidi/icu/impl/Trie.java new file mode 100755 index 00000000..2b5038ee --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/Trie.java @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ****************************************************************************** + * Copyright (C) 1996-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ****************************************************************************** + */ + +package jdk_internal.bidi.icu.impl; + +import java.io.DataInputStream; +import java.io.InputStream; + +import jdk_internal.bidi.icu.lang.UCharacter; +import jdk_internal.bidi.icu.text.UTF16; + +import java.io.IOException; + +/** + *

+ * A trie is a kind of compressed, serializable table of values associated with + * Unicode code points (0..0x10ffff). + *

+ *

+ * This class defines the basic structure of a trie and provides methods to + * retrieve the offsets to the actual data. + *

+ *

+ * Data will be the form of an array of basic types, char or int. + *

+ *

+ * The actual data format will have to be specified by the user in the inner + * static interface com.ibm.icu.impl.Trie.DataManipulate. + *

+ *

+ * This trie implementation is optimized for getting offset while walking + * forward through a UTF-16 string. Therefore, the simplest and fastest access + * macros are the fromLead() and fromOffsetTrail() methods. The fromBMP() method + * are a little more complicated; they get offsets even for lead surrogate + * codepoints, while the fromLead() method get special "folded" offsets for lead + * surrogate code units if there is relevant data associated with them. From + * such a folded offsets, an offset needs to be extracted to supply to the + * fromOffsetTrail() methods. To handle such supplementary codepoints, some + * offset information are kept in the data. + *

+ *

+ * Methods in com.ibm.icu.impl.Trie.DataManipulate are called to retrieve that + * offset from the folded value for the lead surrogate unit. + *

+ *

+ * For examples of use, see com.ibm.icu.impl.CharTrie or + * com.ibm.icu.impl.IntTrie. + *

+ * + * @author synwee + * @see com.ibm.icu.impl.CharTrie + * @see com.ibm.icu.impl.IntTrie + * @since release 2.1, Jan 01 2002 + */ +public abstract class Trie { + // public class declaration ---------------------------------------- + + /** + * Character data in com.ibm.impl.Trie have different user-specified format for + * different purposes. This interface specifies methods to be implemented in + * order for com.ibm.impl.Trie, to surrogate offset information encapsulated + * within the data. + */ + public static interface DataManipulate { + /** + * Called by com.ibm.icu.impl.Trie to extract from a lead surrogate's data the + * index array offset of the indexes for that lead surrogate. + * + * @param value data value for a surrogate from the trie, including the folding + * offset + * @return data offset or 0 if there is no data for the lead surrogate + */ + public int getFoldingOffset(int value); + } + + // default implementation + private static class DefaultGetFoldingOffset implements DataManipulate { + public int getFoldingOffset(int value) { + return value; + } + } + + // protected constructor ------------------------------------------- + + /** + * Trie constructor for CharTrie use. + * + * @param inputStream ICU data file input stream which contains the trie + * @param dataManipulate object containing the information to parse the trie + * data + * @throws IOException thrown when input stream does not have the right header. + */ + protected Trie(InputStream inputStream, DataManipulate dataManipulate) throws IOException { + DataInputStream input = new DataInputStream(inputStream); + // Magic number to authenticate the data. + int signature = input.readInt(); + m_options_ = input.readInt(); + + if (!checkHeader(signature)) { + throw new IllegalArgumentException( + "ICU data file error: Trie header authentication failed, please check if you have the most updated ICU data file"); + } + + if (dataManipulate != null) { + m_dataManipulate_ = dataManipulate; + } else { + m_dataManipulate_ = new DefaultGetFoldingOffset(); + } + m_isLatin1Linear_ = (m_options_ & HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_) != 0; + m_dataOffset_ = input.readInt(); + m_dataLength_ = input.readInt(); + unserialize(inputStream); + } + + // protected data members ------------------------------------------ + + /** + * Lead surrogate code points' index displacement in the index array. + * + *
{@code
+	 * 0x10000-0xd800=0x2800
+	 * 0x2800 >> INDEX_STAGE_1_SHIFT_
+	 * }
+ */ + protected static final int LEAD_INDEX_OFFSET_ = 0x2800 >> 5; + /** + * Shift size for shifting right the input index. 1..9 + */ + protected static final int INDEX_STAGE_1_SHIFT_ = 5; + /** + * Shift size for shifting left the index array values. Increases possible data + * size with 16-bit index values at the cost of compactability. This requires + * blocks of stage 2 data to be aligned by DATA_GRANULARITY. + * 0..INDEX_STAGE_1_SHIFT + */ + protected static final int INDEX_STAGE_2_SHIFT_ = 2; + /** + * Number of data values in a stage 2 (data array) block. + */ + protected static final int DATA_BLOCK_LENGTH = 1 << INDEX_STAGE_1_SHIFT_; + /** + * Mask for getting the lower bits from the input index. DATA_BLOCK_LENGTH - 1. + */ + protected static final int INDEX_STAGE_3_MASK_ = DATA_BLOCK_LENGTH - 1; + /** + * Surrogate mask to use when shifting offset to retrieve supplementary values + */ + protected static final int SURROGATE_MASK_ = 0x3FF; + /** + * Index or UTF16 characters + */ + protected char m_index_[]; + /** + * Internal TrieValue which handles the parsing of the data value. This class is + * to be implemented by the user + */ + protected DataManipulate m_dataManipulate_; + /** + * Start index of the data portion of the trie. CharTrie combines index and data + * into a char array, so this is used to indicate the initial offset to the data + * portion. Note this index always points to the initial value. + */ + protected int m_dataOffset_; + /** + * Length of the data array + */ + protected int m_dataLength_; + + // protected methods ----------------------------------------------- + + /** + * Gets the offset to the data which the surrogate pair points to. + * + * @param lead lead surrogate + * @param trail trailing surrogate + * @return offset to data + */ + protected abstract int getSurrogateOffset(char lead, char trail); + + /** + * Gets the offset to the data which the index ch after variable offset points + * to. Note for locating a non-supplementary character data offset, calling + *

+ * getRawOffset(0, ch); + *

+ * will do. Otherwise if it is a supplementary character formed by surrogates + * lead and trail. Then we would have to call getRawOffset() with + * getFoldingIndexOffset(). See getSurrogateOffset(). + * + * @param offset index offset which ch is to start from + * @param ch index to be used after offset + * @return offset to the data + */ + protected final int getRawOffset(int offset, char ch) { + return (m_index_[offset + (ch >> INDEX_STAGE_1_SHIFT_)] << INDEX_STAGE_2_SHIFT_) + (ch & INDEX_STAGE_3_MASK_); + } + + /** + * Gets the offset to data which the BMP character points to Treats a lead + * surrogate as a normal code point. + * + * @param ch BMP character + * @return offset to data + */ + protected final int getBMPOffset(char ch) { + return (ch >= UTF16.LEAD_SURROGATE_MIN_VALUE && ch <= UTF16.LEAD_SURROGATE_MAX_VALUE) + ? getRawOffset(LEAD_INDEX_OFFSET_, ch) + : getRawOffset(0, ch); + // using a getRawOffset(ch) makes no diff + } + + /** + * Gets the offset to the data which this lead surrogate character points to. + * Data at the returned offset may contain folding offset information for the + * next trailing surrogate character. + * + * @param ch lead surrogate character + * @return offset to data + */ + protected final int getLeadOffset(char ch) { + return getRawOffset(0, ch); + } + + /** + * Internal trie getter from a code point. Could be faster(?) but longer with + * {@code if((c32)<=0xd7ff) { (result)=_TRIE_GET_RAW(trie, data, 0, c32); }} + * Gets the offset to data which the codepoint points to + * + * @param ch codepoint + * @return offset to data + */ + protected final int getCodePointOffset(int ch) { + // if ((ch >> 16) == 0) slower + if (ch < 0) { + return -1; + } else if (ch < UTF16.LEAD_SURROGATE_MIN_VALUE) { + // fastpath for the part of the BMP below surrogates (D800) where getRawOffset() + // works + return getRawOffset(0, (char) ch); + } else if (ch < UTF16.SUPPLEMENTARY_MIN_VALUE) { + // BMP codepoint + return getBMPOffset((char) ch); + } else if (ch <= UCharacter.MAX_VALUE) { + // look at the construction of supplementary characters + // trail forms the ends of it. + return getSurrogateOffset(UTF16.getLeadSurrogate(ch), (char) (ch & SURROGATE_MASK_)); + } else { + // return -1 if there is an error, in this case we return + return -1; + } + } + + /** + *

+ * Parses the inputstream and creates the trie index with it. + *

+ *

+ * This is overwritten by the child classes. + * + * @param inputStream input stream containing the trie information + * @exception IOException thrown when data reading fails. + */ + protected void unserialize(InputStream inputStream) throws IOException { + // indexLength is a multiple of 1024 >> INDEX_STAGE_2_SHIFT_ + m_index_ = new char[m_dataOffset_]; + DataInputStream input = new DataInputStream(inputStream); + for (int i = 0; i < m_dataOffset_; i++) { + m_index_[i] = input.readChar(); + } + } + + /** + * Determines if this is a 16 bit trie + * + * @return true if this is a 16 bit trie + */ + protected final boolean isCharTrie() { + return (m_options_ & HEADER_OPTIONS_DATA_IS_32_BIT_) == 0; + } + + // private data members -------------------------------------------- + + /** + * Latin 1 option mask + */ + protected static final int HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_ = 0x200; + /** + * Constant number to authenticate the byte block + */ + protected static final int HEADER_SIGNATURE_ = 0x54726965; + /** + * Header option formatting + */ + private static final int HEADER_OPTIONS_SHIFT_MASK_ = 0xF; + protected static final int HEADER_OPTIONS_INDEX_SHIFT_ = 4; + protected static final int HEADER_OPTIONS_DATA_IS_32_BIT_ = 0x100; + + /** + * Flag indicator for Latin quick access data block + */ + private boolean m_isLatin1Linear_; + + /** + *

+ * Trie options field. + *

+ *

+ * options bit field:
+ * 9 1 = Latin-1 data is stored linearly at data + DATA_BLOCK_LENGTH
+ * 8 0 = 16-bit data, 1=32-bit data
+ * 7..4 INDEX_STAGE_1_SHIFT // 0..INDEX_STAGE_2_SHIFT
+ * 3..0 INDEX_STAGE_2_SHIFT // 1..9
+ */ + private int m_options_; + + // private methods --------------------------------------------------- + + /** + * Authenticates raw data header. Checking the header information, signature and + * options. + * + * @param signature This contains the options and type of a Trie + * @return true if the header is authenticated valid + */ + private final boolean checkHeader(int signature) { + // check the signature + // Trie in big-endian US-ASCII (0x54726965). + // Magic number to authenticate the data. + if (signature != HEADER_SIGNATURE_) { + return false; + } + + if ((m_options_ & HEADER_OPTIONS_SHIFT_MASK_) != INDEX_STAGE_1_SHIFT_ + || ((m_options_ >> HEADER_OPTIONS_INDEX_SHIFT_) & HEADER_OPTIONS_SHIFT_MASK_) != INDEX_STAGE_2_SHIFT_) { + return false; + } + return true; + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/Trie2.java b/src/main/java/jdk_internal/bidi/icu/impl/Trie2.java new file mode 100755 index 00000000..94c72fcd --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/Trie2.java @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.impl; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * This is the interface and common implementation of a Unicode Trie2. It is a + * kind of compressed table that maps from Unicode code points (0..0x10ffff) to + * 16- or 32-bit integer values. It works best when there are ranges of + * characters with the same value, which is generally the case with Unicode + * character properties. + * + * This is the second common version of a Unicode trie (hence the name Trie2). + * + */ +abstract class Trie2 implements Iterable { + + /** + * Create a Trie2 from its serialized form. Inverse of utrie2_serialize(). + * + * Reads from the current position and leaves the buffer after the end of the + * trie. + * + * The serialized format is identical between ICU4C and ICU4J, so this function + * will work with serialized Trie2s from either. + * + * The actual type of the returned Trie2 will be either Trie2_16 or Trie2_32, + * depending on the width of the data. + * + * To obtain the width of the Trie2, check the actual class type of the returned + * Trie2. Or use the createFromSerialized() function of Trie2_16 or Trie2_32, + * which will return only Tries of their specific type/size. + * + * The serialized Trie2 on the stream may be in either little or big endian byte + * order. This allows using serialized Tries from ICU4C without needing to + * consider the byte order of the system that created them. + * + * @param bytes a byte buffer to the serialized form of a UTrie2. + * @return An unserialized Trie2, ready for use. + * @throws IllegalArgumentException if the stream does not contain a serialized + * Trie2. + * @throws IOException if a read error occurs in the buffer. + * + */ + public static Trie2 createFromSerialized(ByteBuffer bytes) throws IOException { + // From ICU4C utrie2_impl.h + // * Trie2 data structure in serialized form: + // * + // * UTrie2Header header; + // * uint16_t index[header.index2Length]; + // * uint16_t data[header.shiftedDataLength<<2]; -- or uint32_t data[...] + // * @internal + // */ + // typedef struct UTrie2Header { + // /** "Tri2" in big-endian US-ASCII (0x54726932) */ + // uint32_t signature; + + // /** + // * options bit field: + // * 15.. 4 reserved (0) + // * 3.. 0 UTrie2ValueBits valueBits + // */ + // uint16_t options; + // + // /** UTRIE2_INDEX_1_OFFSET..UTRIE2_MAX_INDEX_LENGTH */ + // uint16_t indexLength; + // + // /** (UTRIE2_DATA_START_OFFSET..UTRIE2_MAX_DATA_LENGTH)>>UTRIE2_INDEX_SHIFT */ + // uint16_t shiftedDataLength; + // + // /** Null index and data blocks, not shifted. */ + // uint16_t index2NullOffset, dataNullOffset; + // + // /** + // * First code point of the single-value range ending with U+10ffff, + // * rounded up and then shifted right by UTRIE2_SHIFT_1. + // */ + // uint16_t shiftedHighStart; + // } UTrie2Header; + + ByteOrder outerByteOrder = bytes.order(); + try { + UTrie2Header header = new UTrie2Header(); + + /* check the signature */ + header.signature = bytes.getInt(); + switch (header.signature) { + case 0x54726932: + // The buffer is already set to the trie data byte order. + break; + case 0x32697254: + // Temporarily reverse the byte order. + boolean isBigEndian = outerByteOrder == ByteOrder.BIG_ENDIAN; + bytes.order(isBigEndian ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN); + header.signature = 0x54726932; + break; + default: + throw new IllegalArgumentException("Buffer does not contain a serialized UTrie2"); + } + + header.options = bytes.getChar(); + header.indexLength = bytes.getChar(); + header.shiftedDataLength = bytes.getChar(); + header.index2NullOffset = bytes.getChar(); + header.dataNullOffset = bytes.getChar(); + header.shiftedHighStart = bytes.getChar(); + + if ((header.options & UTRIE2_OPTIONS_VALUE_BITS_MASK) != 0) { + throw new IllegalArgumentException("UTrie2 serialized format error."); + } + + Trie2 This; + This = new Trie2_16(); + This.header = header; + + /* get the length values and offsets */ + This.indexLength = header.indexLength; + This.dataLength = header.shiftedDataLength << UTRIE2_INDEX_SHIFT; + This.index2NullOffset = header.index2NullOffset; + This.dataNullOffset = header.dataNullOffset; + This.highStart = header.shiftedHighStart << UTRIE2_SHIFT_1; + This.highValueIndex = This.dataLength - UTRIE2_DATA_GRANULARITY; + This.highValueIndex += This.indexLength; + + // Allocate the Trie2 index array. If the data width is 16 bits, the array also + // includes the space for the data. + + int indexArraySize = This.indexLength; + indexArraySize += This.dataLength; + This.index = new char[indexArraySize]; + + /* Read in the index */ + int i; + for (i = 0; i < This.indexLength; i++) { + This.index[i] = bytes.getChar(); + } + + /* + * Read in the data. 16 bit data goes in the same array as the index. 32 bit + * data goes in its own separate data array. + */ + This.data16 = This.indexLength; + for (i = 0; i < This.dataLength; i++) { + This.index[This.data16 + i] = bytes.getChar(); + } + + This.data32 = null; + This.initialValue = This.index[This.dataNullOffset]; + This.errorValue = This.index[This.data16 + UTRIE2_BAD_UTF8_DATA_OFFSET]; + + return This; + } finally { + bytes.order(outerByteOrder); + } + } + + /** + * Get the value for a code point as stored in the Trie2. + * + * @param codePoint the code point + * @return the value + */ + public abstract int get(int codePoint); + + /** + * Get the trie value for a UTF-16 code unit. + * + * A Trie2 stores two distinct values for input in the lead surrogate range, one + * for lead surrogates, which is the value that will be returned by this + * function, and a second value that is returned by Trie2.get(). + * + * For code units outside of the lead surrogate range, this function returns the + * same result as Trie2.get(). + * + * This function, together with the alternate value for lead surrogates, makes + * possible very efficient processing of UTF-16 strings without first converting + * surrogate pairs to their corresponding 32 bit code point values. + * + * At build-time, enumerate the contents of the Trie2 to see if there is + * non-trivial (non-initialValue) data for any of the supplementary code points + * associated with a lead surrogate. If so, then set a special + * (application-specific) value for the lead surrogate code _unit_, with + * Trie2Writable.setForLeadSurrogateCodeUnit(). + * + * At runtime, use Trie2.getFromU16SingleLead(). If there is non-trivial data + * and the code unit is a lead surrogate, then check if a trail surrogate + * follows. If so, assemble the supplementary code point and look up its value + * with Trie2.get(); otherwise reset the lead surrogate's value or do a code + * point lookup for it. + * + * If there is only trivial data for lead and trail surrogates, then processing + * can often skip them. For example, in normalization or case mapping all + * characters that do not have any mappings are simply copied as is. + * + * @param c the code point or lead surrogate value. + * @return the value + */ + public abstract int getFromU16SingleLead(char c); + + /** + * When iterating over the contents of a Trie2, Elements of this type are + * produced. The iterator will return one item for each contiguous range of + * codepoints having the same value. + * + * When iterating, the same Trie2EnumRange object will be reused and returned + * for each range. If you need to retain complete iteration results, clone each + * returned Trie2EnumRange, or save the range in some other way, before + * advancing to the next iteration step. + */ + public static class Range { + public int startCodePoint; + public int endCodePoint; // Inclusive. + public int value; + public boolean leadSurrogate; + + public boolean equals(Object other) { + if (other == null || !(other.getClass().equals(getClass()))) { + return false; + } + Range tother = (Range) other; + return this.startCodePoint == tother.startCodePoint && this.endCodePoint == tother.endCodePoint + && this.value == tother.value && this.leadSurrogate == tother.leadSurrogate; + } + + public int hashCode() { + int h = initHash(); + h = hashUChar32(h, startCodePoint); + h = hashUChar32(h, endCodePoint); + h = hashInt(h, value); + h = hashByte(h, leadSurrogate ? 1 : 0); + return h; + } + } + + /** + * Create an iterator over the value ranges in this Trie2. Values from the Trie2 + * are not remapped or filtered, but are returned as they are stored in the + * Trie2. + * + * @return an Iterator + */ + public Iterator iterator() { + return iterator(defaultValueMapper); + } + + private static ValueMapper defaultValueMapper = new ValueMapper() { + public int map(int in) { + return in; + } + }; + + /** + * Create an iterator over the value ranges from this Trie2. Values from the + * Trie2 are passed through a caller-supplied remapping function, and it is the + * remapped values that determine the ranges that will be produced by the + * iterator. + * + * + * @param mapper provides a function to remap values obtained from the Trie2. + * @return an Iterator + */ + public Iterator iterator(ValueMapper mapper) { + return new Trie2Iterator(mapper); + } + + /** + * When iterating over the contents of a Trie2, an instance of TrieValueMapper + * may be used to remap the values from the Trie2. The remapped values will be + * used both in determining the ranges of codepoints and as the value to be + * returned for each range. + * + * Example of use, with an anonymous subclass of TrieValueMapper: + * + * + * ValueMapper m = new ValueMapper() { int map(int in) {return in & 0x1f;}; } + * for (Iterator iter = trie.iterator(m); i.hasNext(); ) { + * Trie2EnumRange r = i.next(); ... // Do something with the range r. } + * + */ + public interface ValueMapper { + public int map(int originalVal); + } + + // -------------------------------------------------------------------------------- + // + // Below this point are internal implementation items. No further public API. + // + // -------------------------------------------------------------------------------- + + /** + * Trie2 data structure in serialized form: + * + * UTrie2Header header; uint16_t index[header.index2Length]; uint16_t + * data[header.shiftedDataLength<<2]; -- or uint32_t data[...] + * + * For Java, this is read from the stream into an instance of UTrie2Header. (The + * C version just places a struct over the raw serialized data.) + * + * @internal + */ + static class UTrie2Header { + /** "Tri2" in big-endian US-ASCII (0x54726932) */ + int signature; + + /** + * options bit field (uint16_t): 15.. 4 reserved (0) 3.. 0 UTrie2ValueBits + * valueBits + */ + int options; + + /** UTRIE2_INDEX_1_OFFSET..UTRIE2_MAX_INDEX_LENGTH (uint16_t) */ + int indexLength; + + /** + * (UTRIE2_DATA_START_OFFSET..UTRIE2_MAX_DATA_LENGTH)>>UTRIE2_INDEX_SHIFT + * (uint16_t) + */ + int shiftedDataLength; + + /** Null index and data blocks, not shifted. (uint16_t) */ + int index2NullOffset, dataNullOffset; + + /** + * First code point of the single-value range ending with U+10ffff, rounded up + * and then shifted right by UTRIE2_SHIFT_1. (uint16_t) + */ + int shiftedHighStart; + } + + // + // Data members of UTrie2. + // + UTrie2Header header; + char index[]; // Index array. Includes data for 16 bit Tries. + int data16; // Offset to data portion of the index array, if 16 bit data. + // zero if 32 bit data. + int data32[]; // NULL if 16b data is used via index + + int indexLength; + int dataLength; + int index2NullOffset; // 0xffff if there is no dedicated index-2 null block + int initialValue; + + /** Value returned for out-of-range code points and illegal UTF-8. */ + int errorValue; + + /* Start of the last range which ends at U+10ffff, and its value. */ + int highStart; + int highValueIndex; + + int dataNullOffset; + + /** + * Trie2 constants, defining shift widths, index array lengths, etc. + * + * These are needed for the runtime macros but users can treat these as + * implementation details and skip to the actual public API further below. + */ + + static final int UTRIE2_OPTIONS_VALUE_BITS_MASK = 0x000f; + + /** Shift size for getting the index-1 table offset. */ + static final int UTRIE2_SHIFT_1 = 6 + 5; + + /** Shift size for getting the index-2 table offset. */ + static final int UTRIE2_SHIFT_2 = 5; + + /** + * Difference between the two shift sizes, for getting an index-1 offset from an + * index-2 offset. 6=11-5 + */ + static final int UTRIE2_SHIFT_1_2 = UTRIE2_SHIFT_1 - UTRIE2_SHIFT_2; + + /** + * Number of index-1 entries for the BMP. 32=0x20 This part of the index-1 table + * is omitted from the serialized form. + */ + static final int UTRIE2_OMITTED_BMP_INDEX_1_LENGTH = 0x10000 >> UTRIE2_SHIFT_1; + + /** Number of entries in an index-2 block. 64=0x40 */ + static final int UTRIE2_INDEX_2_BLOCK_LENGTH = 1 << UTRIE2_SHIFT_1_2; + + /** Mask for getting the lower bits for the in-index-2-block offset. */ + static final int UTRIE2_INDEX_2_MASK = UTRIE2_INDEX_2_BLOCK_LENGTH - 1; + + /** Number of entries in a data block. 32=0x20 */ + static final int UTRIE2_DATA_BLOCK_LENGTH = 1 << UTRIE2_SHIFT_2; + + /** Mask for getting the lower bits for the in-data-block offset. */ + static final int UTRIE2_DATA_MASK = UTRIE2_DATA_BLOCK_LENGTH - 1; + + /** + * Shift size for shifting left the index array values. Increases possible data + * size with 16-bit index values at the cost of compactability. This requires + * data blocks to be aligned by UTRIE2_DATA_GRANULARITY. + */ + static final int UTRIE2_INDEX_SHIFT = 2; + + /** The alignment size of a data block. Also the granularity for compaction. */ + static final int UTRIE2_DATA_GRANULARITY = 1 << UTRIE2_INDEX_SHIFT; + + /** + * The part of the index-2 table for U+D800..U+DBFF stores values for lead + * surrogate code _units_ not code _points_. Values for lead surrogate code + * _points_ are indexed with this portion of the table. + * Length=32=0x20=0x400>>UTRIE2_SHIFT_2. (There are 1024=0x400 lead surrogates.) + */ + static final int UTRIE2_LSCP_INDEX_2_OFFSET = 0x10000 >> UTRIE2_SHIFT_2; + static final int UTRIE2_LSCP_INDEX_2_LENGTH = 0x400 >> UTRIE2_SHIFT_2; + + /** Count the lengths of both BMP pieces. 2080=0x820 */ + static final int UTRIE2_INDEX_2_BMP_LENGTH = UTRIE2_LSCP_INDEX_2_OFFSET + UTRIE2_LSCP_INDEX_2_LENGTH; + + /** + * The 2-byte UTF-8 version of the index-2 table follows at offset 2080=0x820. + * Length 32=0x20 for lead bytes C0..DF, regardless of UTRIE2_SHIFT_2. + */ + static final int UTRIE2_UTF8_2B_INDEX_2_OFFSET = UTRIE2_INDEX_2_BMP_LENGTH; + static final int UTRIE2_UTF8_2B_INDEX_2_LENGTH = 0x800 >> 6; /* U+0800 is the first code point after 2-byte UTF-8 */ + + /** + * The index-1 table, only used for supplementary code points, at offset + * 2112=0x840. Variable length, for code points up to highStart, where the last + * single-value range starts. Maximum length 512=0x200=0x100000>>UTRIE2_SHIFT_1. + * (For 0x100000 supplementary code points U+10000..U+10ffff.) + * + * The part of the index-2 table for supplementary code points starts after this + * index-1 table. + * + * Both the index-1 table and the following part of the index-2 table are + * omitted completely if there is only BMP data. + */ + static final int UTRIE2_INDEX_1_OFFSET = UTRIE2_UTF8_2B_INDEX_2_OFFSET + UTRIE2_UTF8_2B_INDEX_2_LENGTH; + + /** + * The illegal-UTF-8 data block follows the ASCII block, at offset 128=0x80. + * Used with linear access for single bytes 0..0xbf for simple error handling. + * Length 64=0x40, not UTRIE2_DATA_BLOCK_LENGTH. + */ + static final int UTRIE2_BAD_UTF8_DATA_OFFSET = 0x80; + + /** + * Implementation class for an iterator over a Trie2. + * + * Iteration over a Trie2 first returns all of the ranges that are indexed by + * code points, then returns the special alternate values for the lead + * surrogates + * + * @internal + */ + class Trie2Iterator implements Iterator { + + // The normal constructor that configures the iterator to cover the complete + // contents of the Trie2 + Trie2Iterator(ValueMapper vm) { + mapper = vm; + nextStart = 0; + limitCP = 0x110000; + doLeadSurrogates = true; + } + + /** + * The main next() function for Trie2 iterators + * + */ + public Range next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + if (nextStart >= limitCP) { + // Switch over from iterating normal code point values to + // doing the alternate lead-surrogate values. + doingCodePoints = false; + nextStart = 0xd800; + } + int endOfRange = 0; + int val = 0; + int mappedVal = 0; + + if (doingCodePoints) { + // Iteration over code point values. + val = get(nextStart); + mappedVal = mapper.map(val); + endOfRange = rangeEnd(nextStart, limitCP, val); + // Loop once for each range in the Trie2 with the same raw (unmapped) value. + // Loop continues so long as the mapped values are the same. + for (;;) { + if (endOfRange >= limitCP - 1) { + break; + } + val = get(endOfRange + 1); + if (mapper.map(val) != mappedVal) { + break; + } + endOfRange = rangeEnd(endOfRange + 1, limitCP, val); + } + } else { + // Iteration over the alternate lead surrogate values. + val = getFromU16SingleLead((char) nextStart); + mappedVal = mapper.map(val); + endOfRange = rangeEndLS((char) nextStart); + // Loop once for each range in the Trie2 with the same raw (unmapped) value. + // Loop continues so long as the mapped values are the same. + for (;;) { + if (endOfRange >= 0xdbff) { + break; + } + val = getFromU16SingleLead((char) (endOfRange + 1)); + if (mapper.map(val) != mappedVal) { + break; + } + endOfRange = rangeEndLS((char) (endOfRange + 1)); + } + } + returnValue.startCodePoint = nextStart; + returnValue.endCodePoint = endOfRange; + returnValue.value = mappedVal; + returnValue.leadSurrogate = !doingCodePoints; + nextStart = endOfRange + 1; + return returnValue; + } + + /** + * + */ + public boolean hasNext() { + return doingCodePoints && (doLeadSurrogates || nextStart < limitCP) || nextStart < 0xdc00; + } + + private int rangeEndLS(char startingLS) { + if (startingLS >= 0xdbff) { + return 0xdbff; + } + + int c; + int val = getFromU16SingleLead(startingLS); + for (c = startingLS + 1; c <= 0x0dbff; c++) { + if (getFromU16SingleLead((char) c) != val) { + break; + } + } + return c - 1; + } + + // + // Iteration State Variables + // + private ValueMapper mapper; + private Range returnValue = new Range(); + // The starting code point for the next range to be returned. + private int nextStart; + // The upper limit for the last normal range to be returned. Normally 0x110000, + // but + // may be lower when iterating over the code points for a single lead surrogate. + private int limitCP; + + // True while iterating over the Trie2 values for code points. + // False while iterating over the alternate values for lead surrogates. + private boolean doingCodePoints = true; + + // True if the iterator should iterate the special values for lead surrogates in + // addition to the normal values for code points. + private boolean doLeadSurrogates = true; + } + + /** + * Find the last character in a contiguous range of characters with the same + * Trie2 value as the input character. + * + * @param c The character to begin with. + * @return The last contiguous character with the same value. + */ + int rangeEnd(int start, int limitp, int val) { + int c; + int limit = Math.min(highStart, limitp); + + for (c = start + 1; c < limit; c++) { + if (get(c) != val) { + break; + } + } + if (c >= highStart) { + c = limitp; + } + return c - 1; + } + + // + // Hashing implementation functions. FNV hash. Respected public domain + // algorithm. + // + private static int initHash() { + return 0x811c9DC5; // unsigned 2166136261 + } + + private static int hashByte(int h, int b) { + h = h * 16777619; + h = h ^ b; + return h; + } + + private static int hashUChar32(int h, int c) { + h = Trie2.hashByte(h, c & 255); + h = Trie2.hashByte(h, (c >> 8) & 255); + h = Trie2.hashByte(h, c >> 16); + return h; + } + + private static int hashInt(int h, int i) { + h = Trie2.hashByte(h, i & 255); + h = Trie2.hashByte(h, (i >> 8) & 255); + h = Trie2.hashByte(h, (i >> 16) & 255); + h = Trie2.hashByte(h, (i >> 24) & 255); + return h; + } + +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/Trie2_16.java b/src/main/java/jdk_internal/bidi/icu/impl/Trie2_16.java new file mode 100755 index 00000000..770754a7 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/Trie2_16.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.impl; + +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * @author aheninger + * + * A read-only Trie2, holding 16 bit data values. + * + * A Trie2 is a highly optimized data structure for mapping from Unicode + * code points (values ranging from 0 to 0x10ffff) to a 16 or 32 bit + * value. + * + * See class Trie2 for descriptions of the API for accessing the + * contents of a trie. + * + * The fundamental data access methods are declared final in this class, + * with the intent that applications might gain a little extra + * performance, when compared with calling the same methods via the + * abstract UTrie2 base class. + */ +public final class Trie2_16 extends Trie2 { + + /** + * Internal constructor, not for general use. + */ + Trie2_16() { + } + + /** + * Create a Trie2 from its serialized form. Inverse of utrie2_serialize(). The + * serialized format is identical between ICU4C and ICU4J, so this function will + * work with serialized Trie2s from either. + * + * The serialized Trie2 in the bytes may be in either little or big endian byte + * order. This allows using serialized Tries from ICU4C without needing to + * consider the byte order of the system that created them. + * + * @param bytes a byte buffer to the serialized form of a UTrie2. + * @return An unserialized Trie2_16, ready for use. + * @throws IllegalArgumentException if the buffer does not contain a serialized + * Trie2. + * @throws IOException if a read error occurs in the buffer. + * @throws ClassCastException if the bytes contain a serialized Trie2_32 + */ + public static Trie2_16 createFromSerialized(ByteBuffer bytes) throws IOException { + return (Trie2_16) Trie2.createFromSerialized(bytes); + } + + /** + * Get the value for a code point as stored in the Trie2. + * + * @param codePoint the code point + * @return the value + */ + @Override + public final int get(int codePoint) { + int value; + int ix; + + if (codePoint >= 0) { + if (codePoint < 0x0d800 || (codePoint > 0x0dbff && codePoint <= 0x0ffff)) { + // Ordinary BMP code point, excluding leading surrogates. + // BMP uses a single level lookup. BMP index starts at offset 0 in the Trie2 + // index. + // 16 bit data is stored in the index array itself. + ix = index[codePoint >> UTRIE2_SHIFT_2]; + ix = (ix << UTRIE2_INDEX_SHIFT) + (codePoint & UTRIE2_DATA_MASK); + value = index[ix]; + return value; + } + if (codePoint <= 0xffff) { + // Lead Surrogate Code Point. A Separate index section is stored for + // lead surrogate code units and code points. + // The main index has the code unit data. + // For this function, we need the code point data. + // Note: this expression could be refactored for slightly improved efficiency, + // but + // surrogate code points will be so rare in practice that it's not worth it. + ix = index[UTRIE2_LSCP_INDEX_2_OFFSET + ((codePoint - 0xd800) >> UTRIE2_SHIFT_2)]; + ix = (ix << UTRIE2_INDEX_SHIFT) + (codePoint & UTRIE2_DATA_MASK); + value = index[ix]; + return value; + } + if (codePoint < highStart) { + // Supplemental code point, use two-level lookup. + ix = (UTRIE2_INDEX_1_OFFSET - UTRIE2_OMITTED_BMP_INDEX_1_LENGTH) + (codePoint >> UTRIE2_SHIFT_1); + ix = index[ix]; + ix += (codePoint >> UTRIE2_SHIFT_2) & UTRIE2_INDEX_2_MASK; + ix = index[ix]; + ix = (ix << UTRIE2_INDEX_SHIFT) + (codePoint & UTRIE2_DATA_MASK); + value = index[ix]; + return value; + } + if (codePoint <= 0x10ffff) { + value = index[highValueIndex]; + return value; + } + } + + // Fall through. The code point is outside of the legal range of 0..0x10ffff. + return errorValue; + } + + /** + * Get a Trie2 value for a UTF-16 code unit. + * + * This function returns the same value as get() if the input character is + * outside of the lead surrogate range + * + * There are two values stored in a Trie2 for inputs in the lead surrogate + * range. This function returns the alternate value, while Trie2.get() returns + * the main value. + * + * @param codeUnit a 16 bit code unit or lead surrogate value. + * @return the value + */ + @Override + public int getFromU16SingleLead(char codeUnit) { + int value; + int ix; + + // Because the input is a 16 bit char, we can skip the tests for it being in + // the BMP range. It is. + ix = index[codeUnit >> UTRIE2_SHIFT_2]; + ix = (ix << UTRIE2_INDEX_SHIFT) + (codeUnit & UTRIE2_DATA_MASK); + value = index[ix]; + return value; + } + + /** + * @return the number of bytes of the serialized trie + */ + public int getSerializedLength() { + return 16 + (header.indexLength + dataLength) * 2; + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/UBiDiProps.java b/src/main/java/jdk_internal/bidi/icu/impl/UBiDiProps.java new file mode 100755 index 00000000..b81ec6b7 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/UBiDiProps.java @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + ******************************************************************************* + * + * Copyright (C) 2004-2014, International Business Machines + * Corporation and others. All Rights Reserved. + * + ******************************************************************************* + * file name: UBiDiProps.java + * encoding: US-ASCII + * tab size: 8 (not used) + * indentation:4 + * + * created on: 2005jan16 + * created by: Markus W. Scherer + * + * Low-level Unicode bidi/shaping properties access. + * Java port of ubidi_props.h/.c. + */ + +package jdk_internal.bidi.icu.impl; + +import java.io.IOException; +import java.nio.ByteBuffer; +import jdk_internal.bidi.icu.lang.UCharacter; + +public final class UBiDiProps { + // constructors etc. --------------------------------------------------- *** + + // port of ubidi_openProps() + private UBiDiProps() throws IOException { + ByteBuffer bytes = ICUBinary.getRequiredData(DATA_FILE_NAME); + readData(bytes); + } + + private void readData(ByteBuffer bytes) throws IOException { + // read the header + ICUBinary.readHeader(bytes, FMT, new IsAcceptable()); + + // read indexes[] + int i, count; + count = bytes.getInt(); + if (count < IX_TOP) { + throw new IOException("indexes[0] too small in " + DATA_FILE_NAME); + } + indexes = new int[count]; + + indexes[0] = count; + for (i = 1; i < count; ++i) { + indexes[i] = bytes.getInt(); + } + + // read the trie + trie = Trie2_16.createFromSerialized(bytes); + int expectedTrieLength = indexes[IX_TRIE_SIZE]; + int trieLength = trie.getSerializedLength(); + if (trieLength > expectedTrieLength) { + throw new IOException(DATA_FILE_NAME + ": not enough bytes for the trie"); + } + // skip padding after trie bytes + ICUBinary.skipBytes(bytes, expectedTrieLength - trieLength); + + // read mirrors[] + count = indexes[IX_MIRROR_LENGTH]; + if (count > 0) { + mirrors = new int[count]; + for (i = 0; i < count; ++i) { + mirrors[i] = bytes.getInt(); + } + } + + // read jgArray[] + count = indexes[IX_JG_LIMIT] - indexes[IX_JG_START]; + jgArray = new byte[count]; + for (i = 0; i < count; ++i) { + jgArray[i] = bytes.get(); + } + + // read jgArray2[] + count = indexes[IX_JG_LIMIT2] - indexes[IX_JG_START2]; + jgArray2 = new byte[count]; + for (i = 0; i < count; ++i) { + jgArray2[i] = bytes.get(); + } + } + + // implement ICUBinary.Authenticate + private static final class IsAcceptable implements ICUBinary.Authenticate { + public boolean isDataVersionAcceptable(byte version[]) { + return version[0] == 2; + } + } + + // property access functions ------------------------------------------- *** + + public final int getClass(int c) { + return getClassFromProps(trie.get(c)); + } + + private final int getMirror(int c, int props) { + int delta = getMirrorDeltaFromProps(props); + if (delta != ESC_MIRROR_DELTA) { + return c + delta; + } else { + /* look for mirror code point in the mirrors[] table */ + int m; + int i, length; + int c2; + + length = indexes[IX_MIRROR_LENGTH]; + + /* linear search */ + for (i = 0; i < length; ++i) { + m = mirrors[i]; + c2 = getMirrorCodePoint(m); + if (c == c2) { + /* found c, return its mirror code point using the index in m */ + return getMirrorCodePoint(mirrors[getMirrorIndex(m)]); + } else if (c < c2) { + break; + } + } + + /* c not found, return it itself */ + return c; + } + } + + public final int getMirror(int c) { + int props = trie.get(c); + return getMirror(c, props); + } + + public final int getJoiningType(int c) { + return (trie.get(c) & JT_MASK) >> JT_SHIFT; + } + + public final int getJoiningGroup(int c) { + int start, limit; + + start = indexes[IX_JG_START]; + limit = indexes[IX_JG_LIMIT]; + if (start <= c && c < limit) { + return (int) jgArray[c - start] & 0xff; + } + start = indexes[IX_JG_START2]; + limit = indexes[IX_JG_LIMIT2]; + if (start <= c && c < limit) { + return (int) jgArray2[c - start] & 0xff; + } + return UCharacter.JoiningGroup.NO_JOINING_GROUP; + } + + public final int getPairedBracketType(int c) { + return (trie.get(c) & BPT_MASK) >> BPT_SHIFT; + } + + public final int getPairedBracket(int c) { + int props = trie.get(c); + if ((props & BPT_MASK) == 0) { + return c; + } else { + return getMirror(c, props); + } + } + + // data members -------------------------------------------------------- *** + private int indexes[]; + private int mirrors[]; + private byte jgArray[]; + private byte jgArray2[]; + + private Trie2_16 trie; + + // data format constants ----------------------------------------------- *** + @SuppressWarnings("deprecation") + private static final String DATA_FILE_NAME = "/assets/eagler/icudt/ubidi.icu"; + + /* format "BiDi" */ + private static final int FMT = 0x42694469; + + /* indexes into indexes[] */ + private static final int IX_TRIE_SIZE = 2; + private static final int IX_MIRROR_LENGTH = 3; + + private static final int IX_JG_START = 4; + private static final int IX_JG_LIMIT = 5; + private static final int IX_JG_START2 = 6; /* new in format version 2.2, ICU 54 */ + private static final int IX_JG_LIMIT2 = 7; + + private static final int IX_TOP = 16; + + // definitions for 16-bit bidi/shaping properties word ----------------- *** + + /* CLASS_SHIFT=0, */ /* bidi class: 5 bits (4..0) */ + private static final int JT_SHIFT = 5; /* joining type: 3 bits (7..5) */ + + private static final int BPT_SHIFT = 8; /* Bidi_Paired_Bracket_Type(bpt): 2 bits (9..8) */ + + private static final int MIRROR_DELTA_SHIFT = 13; /* bidi mirroring delta: 3 bits (15..13) */ + + private static final int CLASS_MASK = 0x0000001f; + private static final int JT_MASK = 0x000000e0; + private static final int BPT_MASK = 0x00000300; + + private static final int getClassFromProps(int props) { + return props & CLASS_MASK; + } + + private static final boolean getFlagFromProps(int props, int shift) { + return ((props >> shift) & 1) != 0; + } + + private static final int getMirrorDeltaFromProps(int props) { + return (short) props >> MIRROR_DELTA_SHIFT; + } + + private static final int ESC_MIRROR_DELTA = -4; + + // definitions for 32-bit mirror table entry --------------------------- *** + + /* the source Unicode code point takes 21 bits (20..0) */ + private static final int MIRROR_INDEX_SHIFT = 21; + + private static final int getMirrorCodePoint(int m) { + return m & 0x1fffff; + } + + private static final int getMirrorIndex(int m) { + return m >>> MIRROR_INDEX_SHIFT; + } + + /* + * public singleton instance + */ + public static final UBiDiProps INSTANCE; + + // This static initializer block must be placed after + // other static member initialization + static { + try { + INSTANCE = new UBiDiProps(); + } catch (IOException e) { + throw new RuntimeException("Missing resource: \"" + DATA_FILE_NAME + "\"; Reason: " + e.getMessage()); + } + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/UCharacterProperty.java b/src/main/java/jdk_internal/bidi/icu/impl/UCharacterProperty.java new file mode 100755 index 00000000..7b77640f --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/UCharacterProperty.java @@ -0,0 +1,627 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + ******************************************************************************* + * Copyright (C) 1996-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.impl; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Iterator; + +import jdk_internal.bidi.icu.lang.UCharacter.HangulSyllableType; +import jdk_internal.bidi.icu.lang.UCharacter.NumericType; +import jdk_internal.bidi.icu.text.UTF16; +import jdk_internal.bidi.icu.text.UnicodeSet; +import jdk_internal.bidi.icu.util.VersionInfo; + +/** + *

+ * Internal class used for Unicode character property database. + *

+ *

+ * This classes store binary data read from uprops.icu. It does not have the + * capability to parse the data into more high-level information. It only + * returns bytes of information when required. + *

+ *

+ * Due to the form most commonly used for retrieval, array of char is used to + * store the binary data. + *

+ *

+ * UCharacterPropertyDB also contains information on accessing indexes to + * significant points in the binary data. + *

+ *

+ * Responsibility for molding the binary data into more meaning form lies on + * UCharacter. + *

+ * + * @author Syn Wee Quek + * @since release 2.1, february 1st 2002 + */ + +public final class UCharacterProperty { + // public data members ----------------------------------------------- + + /* + * public singleton instance + */ + public static final UCharacterProperty INSTANCE; + + /** + * Trie data + */ + public Trie2_16 m_trie_; + + /** + * Unicode version + */ + public VersionInfo m_unicodeVersion_; + + /** + * Character type mask + */ + public static final int TYPE_MASK = 0x1F; + + // uprops.h enum UPropertySource --------------------------------------- *** + + /** From uchar.c/uprops.icu main trie */ + public static final int SRC_CHAR = 1; + /** From uchar.c/uprops.icu properties vectors trie */ + public static final int SRC_PROPSVEC = 2; + /** From ubidi_props.c/ubidi.icu */ + public static final int SRC_BIDI = 5; + /** From normalizer2impl.cpp/nfc.nrm */ + public static final int SRC_NFC = 8; + /** From normalizer2impl.cpp/nfkc.nrm */ + public static final int SRC_NFKC = 9; + + // public methods ---------------------------------------------------- + + /** + * Gets the main property value for code point ch. + * + * @param ch code point whose property value is to be retrieved + * @return property value of code point + */ + public final int getProperty(int ch) { + return m_trie_.get(ch); + } + + /** + * Gets the unicode additional properties. Java version of C + * u_getUnicodeProperties(). + * + * @param codepoint codepoint whose additional properties is to be retrieved + * @param column The column index. + * @return unicode properties + */ + public int getAdditional(int codepoint, int column) { + assert column >= 0; + if (column >= m_additionalColumnsCount_) { + return 0; + } + return m_additionalVectors_[m_additionalTrie_.get(codepoint) + column]; + } + + /** + *

+ * Get the "age" of the code point. + *

+ *

+ * The "age" is the Unicode version when the code point was first designated (as + * a non-character or for Private Use) or assigned a character. + *

+ *

+ * This can be useful to avoid emitting code points to receiving processes that + * do not accept newer characters. + *

+ *

+ * The data is from the UCD file DerivedAge.txt. + *

+ *

+ * This API does not check the validity of the codepoint. + *

+ * + * @param codepoint The code point. + * @return the Unicode version number + */ + public VersionInfo getAge(int codepoint) { + int version = getAdditional(codepoint, 0) >> AGE_SHIFT_; + return VersionInfo.getInstance((version >> FIRST_NIBBLE_SHIFT_) & LAST_NIBBLE_MASK_, + version & LAST_NIBBLE_MASK_, 0, 0); + } + + // int-value and enumerated properties --------------------------------- *** + + public int getType(int c) { + return getProperty(c) & TYPE_MASK; + } + + /* + * Map some of the Grapheme Cluster Break values to Hangul Syllable Types. + * Hangul_Syllable_Type is fully redundant with a subset of + * Grapheme_Cluster_Break. + */ + private static final int /* UHangulSyllableType */ gcbToHst[] = { HangulSyllableType.NOT_APPLICABLE, /* + * U_GCB_OTHER + */ + HangulSyllableType.NOT_APPLICABLE, /* U_GCB_CONTROL */ + HangulSyllableType.NOT_APPLICABLE, /* U_GCB_CR */ + HangulSyllableType.NOT_APPLICABLE, /* U_GCB_EXTEND */ + HangulSyllableType.LEADING_JAMO, /* U_GCB_L */ + HangulSyllableType.NOT_APPLICABLE, /* U_GCB_LF */ + HangulSyllableType.LV_SYLLABLE, /* U_GCB_LV */ + HangulSyllableType.LVT_SYLLABLE, /* U_GCB_LVT */ + HangulSyllableType.TRAILING_JAMO, /* U_GCB_T */ + HangulSyllableType.VOWEL_JAMO /* U_GCB_V */ + /* + * Omit GCB values beyond what we need for hst. The code below checks for the + * array length. + */ + }; + + private class IntProperty { + int column; // SRC_PROPSVEC column, or "source" if mask==0 + int mask; + int shift; + + IntProperty(int column, int mask, int shift) { + this.column = column; + this.mask = mask; + this.shift = shift; + } + + IntProperty(int source) { + this.column = source; + this.mask = 0; + } + + int getValue(int c) { + // systematic, directly stored properties + return (getAdditional(c, column) & mask) >>> shift; + } + } + + private class BiDiIntProperty extends IntProperty { + BiDiIntProperty() { + super(SRC_BIDI); + } + } + + private class CombiningClassIntProperty extends IntProperty { + CombiningClassIntProperty(int source) { + super(source); + } + } + + private class NormQuickCheckIntProperty extends IntProperty { // UCHAR_NF*_QUICK_CHECK properties + int which; + int max; + + NormQuickCheckIntProperty(int source, int which, int max) { + super(source); + this.which = which; + this.max = max; + } + } + + private IntProperty intProp = new BiDiIntProperty() { // BIDI_PAIRED_BRACKET_TYPE + int getValue(int c) { + return UBiDiProps.INSTANCE.getPairedBracketType(c); + } + }; + + public int getIntPropertyValue(int c, int which) { + if (which == BIDI_PAIRED_BRACKET_TYPE) { + return intProp.getValue(c); + } + return 0; // undefined + } + + /** + * Forms a supplementary code point from the argument character
+ * Note this is for internal use hence no checks for the validity of the + * surrogate characters are done + * + * @param lead lead surrogate character + * @param trail trailing surrogate character + * @return code point of the supplementary character + */ + public static int getRawSupplementary(char lead, char trail) { + return (lead << LEAD_SURROGATE_SHIFT_) + trail + SURROGATE_OFFSET_; + } + + /** + * Gets the type mask + * + * @param type character type + * @return mask + */ + public static final int getMask(int type) { + return 1 << type; + } + + /** + * Returns the digit values of characters like 'A' - 'Z', normal, half-width and + * full-width. This method assumes that the other digit characters are checked + * by the calling method. + * + * @param ch character to test + * @return -1 if ch is not a character of the form 'A' - 'Z', otherwise its + * corresponding digit will be returned. + */ + public static int getEuropeanDigit(int ch) { + if ((ch > 0x7a && ch < 0xff21) || ch < 0x41 || (ch > 0x5a && ch < 0x61) || ch > 0xff5a + || (ch > 0xff3a && ch < 0xff41)) { + return -1; + } + if (ch <= 0x7a) { + // ch >= 0x41 or ch < 0x61 + return ch + 10 - ((ch <= 0x5a) ? 0x41 : 0x61); + } + // ch >= 0xff21 + if (ch <= 0xff3a) { + return ch + 10 - 0xff21; + } + // ch >= 0xff41 && ch <= 0xff5a + return ch + 10 - 0xff41; + } + + public int digit(int c) { + int value = getNumericTypeValue(getProperty(c)) - NTV_DECIMAL_START_; + if (value <= 9) { + return value; + } else { + return -1; + } + } + + // protected variables ----------------------------------------------- + + /** + * Extra property trie + */ + Trie2_16 m_additionalTrie_; + /** + * Extra property vectors, 1st column for age and second for binary properties. + */ + int m_additionalVectors_[]; + /** + * Number of additional columns + */ + int m_additionalColumnsCount_; + /** + * Maximum values for block, bits used as in vector word 0 + */ + int m_maxBlockScriptValue_; + /** + * Maximum values for script, bits used as in vector word 0 + */ + int m_maxJTGValue_; + /** + * Script_Extensions data + */ + public char[] m_scriptExtensions_; + + // private variables ------------------------------------------------- + + /** + * Default name of the datafile + */ + @SuppressWarnings("deprecation") + private static final String DATA_FILE_NAME_ = "/assets/eagler/icudt/uprops.icu"; + + /** + * Shift value for lead surrogate to form a supplementary character. + */ + private static final int LEAD_SURROGATE_SHIFT_ = 10; + /** + * Offset to add to combined surrogate pair to avoid masking. + */ + private static final int SURROGATE_OFFSET_ = UTF16.SUPPLEMENTARY_MIN_VALUE + - (UTF16.SURROGATE_MIN_VALUE << LEAD_SURROGATE_SHIFT_) - UTF16.TRAIL_SURROGATE_MIN_VALUE; + + // property data constants ------------------------------------------------- + + /** + * Numeric types and values in the main properties words. + */ + private static final int NUMERIC_TYPE_VALUE_SHIFT_ = 6; + + private static final int getNumericTypeValue(int props) { + return props >> NUMERIC_TYPE_VALUE_SHIFT_; + } + + /* constants for the storage form of numeric types and values */ + /** No numeric value. */ + private static final int NTV_NONE_ = 0; + /** Decimal digits: nv=0..9 */ + private static final int NTV_DECIMAL_START_ = 1; + /** Other digits: nv=0..9 */ + private static final int NTV_DIGIT_START_ = 11; + /** Small integers: nv=0..154 */ + private static final int NTV_NUMERIC_START_ = 21; + + private static final int ntvGetType(int ntv) { + return (ntv == NTV_NONE_) ? NumericType.NONE + : (ntv < NTV_DIGIT_START_) ? NumericType.DECIMAL + : (ntv < NTV_NUMERIC_START_) ? NumericType.DIGIT : NumericType.NUMERIC; + } + + /* + * Properties in vector word 0 Bits 31..24 DerivedAge version major/minor one + * nibble each 23..22 3..1: Bits 21..20 & 7..0 = Script_Extensions index 3: + * Script value from Script_Extensions 2: Script=Inherited 1: Script=Common 0: + * Script=bits 21..20 & 7..0 21..20 Bits 9..8 of the UScriptCode, or index to + * Script_Extensions 19..17 East Asian Width 16.. 8 UBlockCode 7.. 0 + * UScriptCode, or index to Script_Extensions + */ + + /** + * Script_Extensions: mask includes Script + */ + public static final int SCRIPT_X_MASK = 0x00f000ff; + // private static final int SCRIPT_X_SHIFT = 22; + + // The UScriptCode or Script_Extensions index is split across two bit fields. + // (Starting with Unicode 13/ICU 66/2019 due to more varied Script_Extensions.) + // Shift the high bits right by 12 to assemble the full value. + public static final int SCRIPT_HIGH_MASK = 0x00300000; + public static final int SCRIPT_HIGH_SHIFT = 12; + public static final int MAX_SCRIPT = 0x3ff; + + /** + * Integer properties mask and shift values for East Asian cell width. + * Equivalent to icu4c UPROPS_EA_MASK + */ + private static final int EAST_ASIAN_MASK_ = 0x000e0000; + /** + * Integer properties mask and shift values for East Asian cell width. + * Equivalent to icu4c UPROPS_EA_SHIFT + */ + private static final int EAST_ASIAN_SHIFT_ = 17; + /** + * Integer properties mask and shift values for blocks. Equivalent to icu4c + * UPROPS_BLOCK_MASK + */ + private static final int BLOCK_MASK_ = 0x0001ff00; + /** + * Integer properties mask and shift values for blocks. Equivalent to icu4c + * UPROPS_BLOCK_SHIFT + */ + private static final int BLOCK_SHIFT_ = 8; + /** + * Integer properties mask and shift values for scripts. Equivalent to icu4c + * UPROPS_SHIFT_LOW_MASK. + */ + public static final int SCRIPT_LOW_MASK = 0x000000ff; + + public static final int mergeScriptCodeOrIndex(int scriptX) { + return ((scriptX & SCRIPT_HIGH_MASK) >> SCRIPT_HIGH_SHIFT) | (scriptX & SCRIPT_LOW_MASK); + } + + /** + * Additional properties used in internal trie data + */ + /* + * Properties in vector word 1 Each bit encodes one binary property. The + * following constants represent the bit number, use 1< expectedTrieLength) { + throw new IOException("uprops.icu: not enough bytes for main trie"); + } + // skip padding after trie bytes + ICUBinary.skipBytes(bytes, expectedTrieLength - trieLength); + + // skip unused intervening data structures + ICUBinary.skipBytes(bytes, (additionalOffset - propertyOffset) * 4); + + if (m_additionalColumnsCount_ > 0) { + // reads the additional property block + m_additionalTrie_ = Trie2_16.createFromSerialized(bytes); + expectedTrieLength = (additionalVectorsOffset - additionalOffset) * 4; + trieLength = m_additionalTrie_.getSerializedLength(); + if (trieLength > expectedTrieLength) { + throw new IOException("uprops.icu: not enough bytes for additional-properties trie"); + } + // skip padding after trie bytes + ICUBinary.skipBytes(bytes, expectedTrieLength - trieLength); + + // additional properties + int size = scriptExtensionsOffset - additionalVectorsOffset; + m_additionalVectors_ = new int[size]; + for (int i = 0; i < size; i++) { + m_additionalVectors_[i] = bytes.getInt(); + } + } + + // Script_Extensions + int numChars = (reservedOffset7 - scriptExtensionsOffset) * 2; + if (numChars > 0) { + m_scriptExtensions_ = new char[numChars]; + for (int i = 0; i < numChars; ++i) { + m_scriptExtensions_[i] = bytes.getChar(); + } + } + } + + private static final class IsAcceptable implements ICUBinary.Authenticate { + // @Override when we switch to Java 6 + public boolean isDataVersionAcceptable(byte version[]) { + return version[0] == 7; + } + } + + private static final int DATA_FORMAT = 0x5550726F; // "UPro" + + public void upropsvec_addPropertyStarts(UnicodeSet set) { + /* + * add the start code point of each same-value range of the properties vectors + * trie + */ + if (m_additionalColumnsCount_ > 0) { + /* + * if m_additionalColumnsCount_==0 then the properties vectors trie may not be + * there at all + */ + Iterator trieIterator = m_additionalTrie_.iterator(); + Trie2.Range range; + while (trieIterator.hasNext() && !(range = trieIterator.next()).leadSurrogate) { + set.add(range.startCodePoint); + } + } + } + + // This static initializer block must be placed after + // other static member initialization + static { + try { + INSTANCE = new UCharacterProperty(); + } catch (IOException e) { + throw new RuntimeException("Missing resource: \"" + DATA_FILE_NAME_ + "\"; Reason: " + e.getMessage()); + } + } + + // Moved from UProperty.java + /** + * Enumerated property Bidi_Paired_Bracket_Type (new in Unicode 6.3). Used in + * UAX #9: Unicode Bidirectional Algorithm (http://www.unicode.org/reports/tr9/) + * Returns UCharacter.BidiPairedBracketType values. + * + * @stable ICU 52 + */ + public static final int BIDI_PAIRED_BRACKET_TYPE = 0x1015; + +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/UnicodeSetStringSpan.java b/src/main/java/jdk_internal/bidi/icu/impl/UnicodeSetStringSpan.java new file mode 100755 index 00000000..c89f8b09 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/UnicodeSetStringSpan.java @@ -0,0 +1,1179 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ****************************************************************************** + * + * Copyright (C) 2009-2014, International Business Machines + * Corporation and others. All Rights Reserved. + * + ****************************************************************************** + */ + +package jdk_internal.bidi.icu.impl; + +import java.util.ArrayList; + +import jdk_internal.bidi.icu.text.UTF16; +import jdk_internal.bidi.icu.text.UnicodeSet; +import jdk_internal.bidi.icu.text.UnicodeSet.SpanCondition; +import jdk_internal.bidi.icu.util.OutputInt; + +/* + * Implement span() etc. for a set with strings. + * Avoid recursion because of its exponential complexity. + * Instead, try multiple paths at once and track them with an IndexList. + */ +public class UnicodeSetStringSpan { + + /* + * Which span() variant will be used? The object is either built for one variant + * and used once, or built for all and may be used many times. + */ + public static final int WITH_COUNT = 0x40; // spanAndCount() may be called + public static final int FWD = 0x20; + public static final int BACK = 0x10; + // public static final int UTF16 = 8; + public static final int CONTAINED = 2; + public static final int NOT_CONTAINED = 1; + + public static final int ALL = 0x7f; + + public static final int FWD_UTF16_CONTAINED = FWD | /* UTF16 | */ CONTAINED; + public static final int FWD_UTF16_NOT_CONTAINED = FWD | /* UTF16 | */NOT_CONTAINED; + public static final int BACK_UTF16_CONTAINED = BACK | /* UTF16 | */ CONTAINED; + public static final int BACK_UTF16_NOT_CONTAINED = BACK | /* UTF16 | */NOT_CONTAINED; + + /** + * Special spanLength short values. (since Java has not unsigned byte type) All + * code points in the string are contained in the parent set. + */ + static final short ALL_CP_CONTAINED = 0xff; + + /** The spanLength is >=0xfe. */ + static final short LONG_SPAN = ALL_CP_CONTAINED - 1; + + /** Set for span(). Same as parent but without strings. */ + private UnicodeSet spanSet; + + /** + * Set for span(not contained). Same as spanSet, plus characters that start or + * end strings. + */ + private UnicodeSet spanNotSet; + + /** The strings of the parent set. */ + private ArrayList strings; + + /** The lengths of span(), spanBack() etc. for each string. */ + private short[] spanLengths; + + /** Maximum lengths of relevant strings. */ + private int maxLength16; + + /** Are there strings that are not fully contained in the code point set? */ + private boolean someRelevant; + + /** Set up for all variants of span()? */ + private boolean all; + + /** Span helper */ + private OffsetList offsets; + + /** + * Constructs for all variants of span(), or only for any one variant. + * Initializes as little as possible, for single use. + */ + public UnicodeSetStringSpan(final UnicodeSet set, final ArrayList setStrings, int which) { + spanSet = new UnicodeSet(0, 0x10ffff); + // TODO: With Java 6, just take the parent set's strings as is, + // as a NavigableSet, rather than as an ArrayList copy of the set of + // strings. + // Then iterate via the first() and higher() methods. + // (We do not want to create multiple Iterator objects in each span().) + // See ICU ticket #7454. + strings = setStrings; + all = (which == ALL); + spanSet.retainAll(set); + if (0 != (which & NOT_CONTAINED)) { + // Default to the same sets. + // addToSpanNotSet() will create a separate set if necessary. + spanNotSet = spanSet; + } + offsets = new OffsetList(); + + // Determine if the strings even need to be taken into account at all for span() + // etc. + // If any string is relevant, then all strings need to be used for + // span(longest match) but only the relevant ones for span(while contained). + // TODO: Possible optimization: Distinguish CONTAINED vs. LONGEST_MATCH + // and do not store UTF-8 strings if !thisRelevant and CONTAINED. + // (Only store irrelevant UTF-8 strings for LONGEST_MATCH where they are + // relevant after all.) + // Also count the lengths of the UTF-8 versions of the strings for memory + // allocation. + int stringsLength = strings.size(); + + int i, spanLength; + someRelevant = false; + for (i = 0; i < stringsLength; ++i) { + String string = strings.get(i); + int length16 = string.length(); + spanLength = spanSet.span(string, SpanCondition.CONTAINED); + if (spanLength < length16) { // Relevant string. + someRelevant = true; + } + if (/* (0 != (which & UTF16)) && */ length16 > maxLength16) { + maxLength16 = length16; + } + } + if (!someRelevant && (which & WITH_COUNT) == 0) { + return; + } + + // Freeze after checking for the need to use strings at all because freezing + // a set takes some time and memory which are wasted if there are no relevant + // strings. + if (all) { + spanSet.freeze(); + } + + int spanBackLengthsOffset; + + // Allocate a block of meta data. + int allocSize; + if (all) { + // 2 sets of span lengths + allocSize = stringsLength * (2); + } else { + allocSize = stringsLength; // One set of span lengths. + } + spanLengths = new short[allocSize]; + + if (all) { + // Store span lengths for all span() variants. + spanBackLengthsOffset = stringsLength; + } else { + // Store span lengths for only one span() variant. + spanBackLengthsOffset = 0; + } + + // Set the meta data and spanNotSet and write the UTF-8 strings. + + for (i = 0; i < stringsLength; ++i) { + String string = strings.get(i); + int length16 = string.length(); + spanLength = spanSet.span(string, SpanCondition.CONTAINED); + if (spanLength < length16) { // Relevant string. + if (true /* 0 != (which & UTF16) */) { + if (0 != (which & CONTAINED)) { + if (0 != (which & FWD)) { + spanLengths[i] = makeSpanLengthByte(spanLength); + } + if (0 != (which & BACK)) { + spanLength = length16 - spanSet.spanBack(string, length16, SpanCondition.CONTAINED); + spanLengths[spanBackLengthsOffset + i] = makeSpanLengthByte(spanLength); + } + } else /* not CONTAINED, not all, but NOT_CONTAINED */ { + spanLengths[i] = spanLengths[spanBackLengthsOffset + i] = 0; // Only store a relevant/irrelevant + // flag. + } + } + if (0 != (which & NOT_CONTAINED)) { + // Add string start and end code points to the spanNotSet so that + // a span(while not contained) stops before any string. + int c; + if (0 != (which & FWD)) { + c = string.codePointAt(0); + addToSpanNotSet(c); + } + if (0 != (which & BACK)) { + c = string.codePointBefore(length16); + addToSpanNotSet(c); + } + } + } else { // Irrelevant string. + if (all) { + spanLengths[i] = spanLengths[spanBackLengthsOffset + i] = ALL_CP_CONTAINED; + } else { + // All spanXYZLengths pointers contain the same address. + spanLengths[i] = ALL_CP_CONTAINED; + } + } + } + + // Finish. + if (all) { + spanNotSet.freeze(); + } + } + + /** + * Do the strings need to be checked in span() etc.? + * + * @return true if strings need to be checked (call span() here), false if not + * (use a BMPSet for best performance). + */ + public boolean needsStringSpanUTF16() { + return someRelevant; + } + + /** For fast UnicodeSet::contains(c). */ + public boolean contains(int c) { + return spanSet.contains(c); + } + + /** + * Adds a starting or ending string character to the spanNotSet so that a + * character span ends before any string. + */ + private void addToSpanNotSet(int c) { + if (spanNotSet == null || spanNotSet == spanSet) { + if (spanSet.contains(c)) { + return; // Nothing to do. + } + spanNotSet = spanSet.cloneAsThawed(); + } + spanNotSet.add(c); + } + + /* + * Note: In span() when spanLength==0 (after a string match, or at the beginning + * after an empty code point span) and in spanNot() and spanNotUTF8(), string + * matching could use a binary search because all string matches are done from + * the same start index. + * + * For UTF-8, this would require a comparison function that returns UTF-16 + * order. + * + * This optimization should not be necessary for normal UnicodeSets because most + * sets have no strings, and most sets with strings have very few very short + * strings. For cases with many strings, it might be better to use a different + * API and implementation with a DFA (state machine). + */ + + /* + * Algorithm for span(SpanCondition.CONTAINED) + * + * Theoretical algorithm: - Iterate through the string, and at each code point + * boundary: + If the code point there is in the set, then remember to continue + * after it. + If a set string matches at the current position, then remember to + * continue after it. + Either recursively span for each code point or string + * match, or recursively span for all but the shortest one and iteratively + * continue the span with the shortest local match. + Remember the longest + * recursive span (the farthest end point). + If there is no match at the + * current position, neither for the code point there nor for any set string, + * then stop and return the longest recursive span length. + * + * Optimized implementation: + * + * (We assume that most sets will have very few very short strings. A span using + * a string-less set is extremely fast.) + * + * Create and cache a spanSet which contains all of the single code points of + * the original set but none of its strings. + * + * - Start with spanLength=spanSet.span(SpanCondition.CONTAINED). - Loop: + Try + * to match each set string at the end of the spanLength. ~ Set strings that + * start with set-contained code points must be matched with a partial overlap + * because the recursive algorithm would have tried to match them at every + * position. ~ Set strings that entirely consist of set-contained code points + * are irrelevant for span(SpanCondition.CONTAINED) because the recursive + * algorithm would continue after them anyway and find the longest recursive + * match from their end. ~ Rather than recursing, note each end point of a set + * string match. + If no set string matched after spanSet.span(), then return + * with where the spanSet.span() ended. + If at least one set string matched + * after spanSet.span(), then pop the shortest string match end point and + * continue the loop, trying to match all set strings from there. + If at least + * one more set string matched after a previous string match, then test if the + * code point after the previous string match is also contained in the set. + * Continue the loop with the shortest end point of either this code point or a + * matching set string. + If no more set string matched after a previous string + * match, then try another spanLength=spanSet.span(SpanCondition.CONTAINED). + * Stop if spanLength==0, otherwise continue the loop. + * + * By noting each end point of a set string match, the function visits each + * string position at most once and finishes in linear time. + * + * The recursive algorithm may visit the same string position many times if + * multiple paths lead to it and finishes in exponential time. + */ + + /* + * Algorithm for span(SIMPLE) + * + * Theoretical algorithm: - Iterate through the string, and at each code point + * boundary: + If the code point there is in the set, then remember to continue + * after it. + If a set string matches at the current position, then remember to + * continue after it. + Continue from the farthest match position and ignore all + * others. + If there is no match at the current position, then stop and return + * the current position. + * + * Optimized implementation: + * + * (Same assumption and spanSet as above.) + * + * - Start with spanLength=spanSet.span(SpanCondition.CONTAINED). - Loop: + Try + * to match each set string at the end of the spanLength. ~ Set strings that + * start with set-contained code points must be matched with a partial overlap + * because the standard algorithm would have tried to match them earlier. ~ Set + * strings that entirely consist of set-contained code points must be matched + * with a full overlap because the longest-match algorithm would hide set string + * matches that end earlier. Such set strings need not be matched earlier inside + * the code point span because the standard algorithm would then have continued + * after the set string match anyway. ~ Remember the longest set string match + * (farthest end point) from the earliest starting point. + If no set string + * matched after spanSet.span(), then return with where the spanSet.span() + * ended. + If at least one set string matched, then continue the loop after the + * longest match from the earliest position. + If no more set string matched + * after a previous string match, then try another + * spanLength=spanSet.span(SpanCondition.CONTAINED). Stop if spanLength==0, + * otherwise continue the loop. + */ + /** + * Spans a string. + * + * @param s The string to be spanned + * @param start The start index that the span begins + * @param spanCondition The span condition + * @return the limit (exclusive end) of the span + */ + public int span(CharSequence s, int start, SpanCondition spanCondition) { + if (spanCondition == SpanCondition.NOT_CONTAINED) { + return spanNot(s, start, null); + } + int spanLimit = spanSet.span(s, start, SpanCondition.CONTAINED); + if (spanLimit == s.length()) { + return spanLimit; + } + return spanWithStrings(s, start, spanLimit, spanCondition); + } + + /** + * Synchronized method for complicated spans using the offsets. Avoids + * synchronization for simple cases. + * + * @param spanLimit = spanSet.span(s, start, CONTAINED) + */ + private synchronized int spanWithStrings(CharSequence s, int start, int spanLimit, SpanCondition spanCondition) { + // Consider strings; they may overlap with the span. + int initSize = 0; + if (spanCondition == SpanCondition.CONTAINED) { + // Use offset list to try all possibilities. + initSize = maxLength16; + } + offsets.setMaxLength(initSize); + int length = s.length(); + int pos = spanLimit, rest = length - spanLimit; + int spanLength = spanLimit - start; + int i, stringsLength = strings.size(); + for (;;) { + if (spanCondition == SpanCondition.CONTAINED) { + for (i = 0; i < stringsLength; ++i) { + int overlap = spanLengths[i]; + if (overlap == ALL_CP_CONTAINED) { + continue; // Irrelevant string. + } + String string = strings.get(i); + + int length16 = string.length(); + + // Try to match this string at pos-overlap..pos. + if (overlap >= LONG_SPAN) { + overlap = length16; + // While contained: No point matching fully inside the code point span. + overlap = string.offsetByCodePoints(overlap, -1); // Length of the string minus the last code + // point. + } + if (overlap > spanLength) { + overlap = spanLength; + } + int inc = length16 - overlap; // Keep overlap+inc==length16. + for (;;) { + if (inc > rest) { + break; + } + // Try to match if the increment is not listed already. + if (!offsets.containsOffset(inc) && matches16CPB(s, pos - overlap, length, string, length16)) { + if (inc == rest) { + return length; // Reached the end of the string. + } + offsets.addOffset(inc); + } + if (overlap == 0) { + break; + } + --overlap; + ++inc; + } + } + } else /* SIMPLE */ { + int maxInc = 0, maxOverlap = 0; + for (i = 0; i < stringsLength; ++i) { + int overlap = spanLengths[i]; + // For longest match, we do need to try to match even an all-contained string + // to find the match from the earliest start. + + String string = strings.get(i); + + int length16 = string.length(); + + // Try to match this string at pos-overlap..pos. + if (overlap >= LONG_SPAN) { + overlap = length16; + // Longest match: Need to match fully inside the code point span + // to find the match from the earliest start. + } + if (overlap > spanLength) { + overlap = spanLength; + } + int inc = length16 - overlap; // Keep overlap+inc==length16. + for (;;) { + if (inc > rest || overlap < maxOverlap) { + break; + } + // Try to match if the string is longer or starts earlier. + if ((overlap > maxOverlap || /* redundant overlap==maxOverlap && */inc > maxInc) + && matches16CPB(s, pos - overlap, length, string, length16)) { + maxInc = inc; // Longest match from earliest start. + maxOverlap = overlap; + break; + } + --overlap; + ++inc; + } + } + + if (maxInc != 0 || maxOverlap != 0) { + // Longest-match algorithm, and there was a string match. + // Simply continue after it. + pos += maxInc; + rest -= maxInc; + if (rest == 0) { + return length; // Reached the end of the string. + } + spanLength = 0; // Match strings from after a string match. + continue; + } + } + // Finished trying to match all strings at pos. + + if (spanLength != 0 || pos == 0) { + // The position is after an unlimited code point span (spanLength!=0), + // not after a string match. + // The only position where spanLength==0 after a span is pos==0. + // Otherwise, an unlimited code point span is only tried again when no + // strings match, and if such a non-initial span fails we stop. + if (offsets.isEmpty()) { + return pos; // No strings matched after a span. + } + // Match strings from after the next string match. + } else { + // The position is after a string match (or a single code point). + if (offsets.isEmpty()) { + // No more strings matched after a previous string match. + // Try another code point span from after the last string match. + spanLimit = spanSet.span(s, pos, SpanCondition.CONTAINED); + spanLength = spanLimit - pos; + if (spanLength == rest || // Reached the end of the string, or + spanLength == 0 // neither strings nor span progressed. + ) { + return spanLimit; + } + pos += spanLength; + rest -= spanLength; + continue; // spanLength>0: Match strings from after a span. + } else { + // Try to match only one code point from after a string match if some + // string matched beyond it, so that we try all possible positions + // and don't overshoot. + spanLength = spanOne(spanSet, s, pos, rest); + if (spanLength > 0) { + if (spanLength == rest) { + return length; // Reached the end of the string. + } + // Match strings after this code point. + // There cannot be any increments below it because UnicodeSet strings + // contain multiple code points. + pos += spanLength; + rest -= spanLength; + offsets.shift(spanLength); + spanLength = 0; + continue; // Match strings from after a single code point. + } + // Match strings from after the next string match. + } + } + int minOffset = offsets.popMinimum(null); + pos += minOffset; + rest -= minOffset; + spanLength = 0; // Match strings from after a string match. + } + } + + /** + * Spans a string and counts the smallest number of set elements on any path + * across the span. + * + *

+ * For proper counting, we cannot ignore strings that are fully contained in + * code point spans. + * + *

+ * If the set does not have any fully-contained strings, then we could optimize + * this like span(), but such sets are likely rare, and this is at least still + * linear. + * + * @param s The string to be spanned + * @param start The start index that the span begins + * @param spanCondition The span condition + * @param outCount The count + * @return the limit (exclusive end) of the span + */ + public int spanAndCount(CharSequence s, int start, SpanCondition spanCondition, OutputInt outCount) { + if (spanCondition == SpanCondition.NOT_CONTAINED) { + return spanNot(s, start, outCount); + } + // Consider strings; they may overlap with the span, + // and they may result in a smaller count that with just code points. + if (spanCondition == SpanCondition.CONTAINED) { + return spanContainedAndCount(s, start, outCount); + } + // SIMPLE (not synchronized, does not use offsets) + int stringsLength = strings.size(); + int length = s.length(); + int pos = start; + int rest = length - start; + int count = 0; + while (rest != 0) { + // Try to match the next code point. + int cpLength = spanOne(spanSet, s, pos, rest); + int maxInc = (cpLength > 0) ? cpLength : 0; + // Try to match all of the strings. + for (int i = 0; i < stringsLength; ++i) { + String string = strings.get(i); + int length16 = string.length(); + if (maxInc < length16 && length16 <= rest && matches16CPB(s, pos, length, string, length16)) { + maxInc = length16; + } + } + // We are done if there is no match beyond pos. + if (maxInc == 0) { + outCount.value = count; + return pos; + } + // Continue from the longest match. + ++count; + pos += maxInc; + rest -= maxInc; + } + outCount.value = count; + return pos; + } + + private synchronized int spanContainedAndCount(CharSequence s, int start, OutputInt outCount) { + // Use offset list to try all possibilities. + offsets.setMaxLength(maxLength16); + int stringsLength = strings.size(); + int length = s.length(); + int pos = start; + int rest = length - start; + int count = 0; + while (rest != 0) { + // Try to match the next code point. + int cpLength = spanOne(spanSet, s, pos, rest); + if (cpLength > 0) { + offsets.addOffsetAndCount(cpLength, count + 1); + } + // Try to match all of the strings. + for (int i = 0; i < stringsLength; ++i) { + String string = strings.get(i); + int length16 = string.length(); + // Note: If the strings were sorted by length, then we could also + // avoid trying to match if there is already a match of the same length. + if (length16 <= rest && !offsets.hasCountAtOffset(length16, count + 1) + && matches16CPB(s, pos, length, string, length16)) { + offsets.addOffsetAndCount(length16, count + 1); + } + } + // We are done if there is no match beyond pos. + if (offsets.isEmpty()) { + outCount.value = count; + return pos; + } + // Continue from the nearest match. + int minOffset = offsets.popMinimum(outCount); + count = outCount.value; + pos += minOffset; + rest -= minOffset; + } + outCount.value = count; + return pos; + } + + /** + * Span a string backwards. + * + * @param s The string to be spanned + * @param spanCondition The span condition + * @return The string index which starts the span (i.e. inclusive). + */ + public synchronized int spanBack(CharSequence s, int length, SpanCondition spanCondition) { + if (spanCondition == SpanCondition.NOT_CONTAINED) { + return spanNotBack(s, length); + } + int pos = spanSet.spanBack(s, length, SpanCondition.CONTAINED); + if (pos == 0) { + return 0; + } + int spanLength = length - pos; + + // Consider strings; they may overlap with the span. + int initSize = 0; + if (spanCondition == SpanCondition.CONTAINED) { + // Use offset list to try all possibilities. + initSize = maxLength16; + } + offsets.setMaxLength(initSize); + int i, stringsLength = strings.size(); + int spanBackLengthsOffset = 0; + if (all) { + spanBackLengthsOffset = stringsLength; + } + for (;;) { + if (spanCondition == SpanCondition.CONTAINED) { + for (i = 0; i < stringsLength; ++i) { + int overlap = spanLengths[spanBackLengthsOffset + i]; + if (overlap == ALL_CP_CONTAINED) { + continue; // Irrelevant string. + } + String string = strings.get(i); + + int length16 = string.length(); + + // Try to match this string at pos-(length16-overlap)..pos-length16. + if (overlap >= LONG_SPAN) { + overlap = length16; + // While contained: No point matching fully inside the code point span. + int len1 = 0; + len1 = string.offsetByCodePoints(0, 1); + overlap -= len1; // Length of the string minus the first code point. + } + if (overlap > spanLength) { + overlap = spanLength; + } + int dec = length16 - overlap; // Keep dec+overlap==length16. + for (;;) { + if (dec > pos) { + break; + } + // Try to match if the decrement is not listed already. + if (!offsets.containsOffset(dec) && matches16CPB(s, pos - dec, length, string, length16)) { + if (dec == pos) { + return 0; // Reached the start of the string. + } + offsets.addOffset(dec); + } + if (overlap == 0) { + break; + } + --overlap; + ++dec; + } + } + } else /* SIMPLE */ { + int maxDec = 0, maxOverlap = 0; + for (i = 0; i < stringsLength; ++i) { + int overlap = spanLengths[spanBackLengthsOffset + i]; + // For longest match, we do need to try to match even an all-contained string + // to find the match from the latest end. + + String string = strings.get(i); + + int length16 = string.length(); + + // Try to match this string at pos-(length16-overlap)..pos-length16. + if (overlap >= LONG_SPAN) { + overlap = length16; + // Longest match: Need to match fully inside the code point span + // to find the match from the latest end. + } + if (overlap > spanLength) { + overlap = spanLength; + } + int dec = length16 - overlap; // Keep dec+overlap==length16. + for (;;) { + if (dec > pos || overlap < maxOverlap) { + break; + } + // Try to match if the string is longer or ends later. + if ((overlap > maxOverlap || /* redundant overlap==maxOverlap && */dec > maxDec) + && matches16CPB(s, pos - dec, length, string, length16)) { + maxDec = dec; // Longest match from latest end. + maxOverlap = overlap; + break; + } + --overlap; + ++dec; + } + } + + if (maxDec != 0 || maxOverlap != 0) { + // Longest-match algorithm, and there was a string match. + // Simply continue before it. + pos -= maxDec; + if (pos == 0) { + return 0; // Reached the start of the string. + } + spanLength = 0; // Match strings from before a string match. + continue; + } + } + // Finished trying to match all strings at pos. + + if (spanLength != 0 || pos == length) { + // The position is before an unlimited code point span (spanLength!=0), + // not before a string match. + // The only position where spanLength==0 before a span is pos==length. + // Otherwise, an unlimited code point span is only tried again when no + // strings match, and if such a non-initial span fails we stop. + if (offsets.isEmpty()) { + return pos; // No strings matched before a span. + } + // Match strings from before the next string match. + } else { + // The position is before a string match (or a single code point). + if (offsets.isEmpty()) { + // No more strings matched before a previous string match. + // Try another code point span from before the last string match. + int oldPos = pos; + pos = spanSet.spanBack(s, oldPos, SpanCondition.CONTAINED); + spanLength = oldPos - pos; + if (pos == 0 || // Reached the start of the string, or + spanLength == 0 // neither strings nor span progressed. + ) { + return pos; + } + continue; // spanLength>0: Match strings from before a span. + } else { + // Try to match only one code point from before a string match if some + // string matched beyond it, so that we try all possible positions + // and don't overshoot. + spanLength = spanOneBack(spanSet, s, pos); + if (spanLength > 0) { + if (spanLength == pos) { + return 0; // Reached the start of the string. + } + // Match strings before this code point. + // There cannot be any decrements below it because UnicodeSet strings + // contain multiple code points. + pos -= spanLength; + offsets.shift(spanLength); + spanLength = 0; + continue; // Match strings from before a single code point. + } + // Match strings from before the next string match. + } + } + pos -= offsets.popMinimum(null); + spanLength = 0; // Match strings from before a string match. + } + } + + /** + * Algorithm for spanNot()==span(SpanCondition.NOT_CONTAINED) + * + * Theoretical algorithm: - Iterate through the string, and at each code point + * boundary: + If the code point there is in the set, then return with the + * current position. + If a set string matches at the current position, then + * return with the current position. + * + * Optimized implementation: + * + * (Same assumption as for span() above.) + * + * Create and cache a spanNotSet which contains all of the single code points of + * the original set but none of its strings. For each set string add its initial + * code point to the spanNotSet. (Also add its final code point for + * spanNotBack().) + * + * - Loop: + Do spanLength=spanNotSet.span(SpanCondition.NOT_CONTAINED). + If + * the current code point is in the original set, then return the current + * position. + If any set string matches at the current position, then return + * the current position. + If there is no match at the current position, neither + * for the code point there nor for any set string, then skip this code point + * and continue the loop. This happens for set-string-initial code points that + * were added to spanNotSet when there is not actually a match for such a set + * string. + * + * @param s The string to be spanned + * @param start The start index that the span begins + * @param outCount If not null: Receives the number of code points across the + * span. + * @return the limit (exclusive end) of the span + */ + private int spanNot(CharSequence s, int start, OutputInt outCount) { + int length = s.length(); + int pos = start, rest = length - start; + int stringsLength = strings.size(); + int count = 0; + do { + // Span until we find a code point from the set, + // or a code point that starts or ends some string. + int spanLimit; + if (outCount == null) { + spanLimit = spanNotSet.span(s, pos, SpanCondition.NOT_CONTAINED); + } else { + spanLimit = spanNotSet.spanAndCount(s, pos, SpanCondition.NOT_CONTAINED, outCount); + outCount.value = count = count + outCount.value; + } + if (spanLimit == length) { + return length; // Reached the end of the string. + } + pos = spanLimit; + rest = length - spanLimit; + + // Check whether the current code point is in the original set, + // without the string starts and ends. + int cpLength = spanOne(spanSet, s, pos, rest); + if (cpLength > 0) { + return pos; // There is a set element at pos. + } + + // Try to match the strings at pos. + for (int i = 0; i < stringsLength; ++i) { + if (spanLengths[i] == ALL_CP_CONTAINED) { + continue; // Irrelevant string. + } + String string = strings.get(i); + + int length16 = string.length(); + if (length16 <= rest && matches16CPB(s, pos, length, string, length16)) { + return pos; // There is a set element at pos. + } + } + + // The span(while not contained) ended on a string start/end which is + // not in the original set. Skip this code point and continue. + // cpLength<0 + pos -= cpLength; + rest += cpLength; + ++count; + } while (rest != 0); + if (outCount != null) { + outCount.value = count; + } + return length; // Reached the end of the string. + } + + private int spanNotBack(CharSequence s, int length) { + int pos = length; + int i, stringsLength = strings.size(); + do { + // Span until we find a code point from the set, + // or a code point that starts or ends some string. + pos = spanNotSet.spanBack(s, pos, SpanCondition.NOT_CONTAINED); + if (pos == 0) { + return 0; // Reached the start of the string. + } + + // Check whether the current code point is in the original set, + // without the string starts and ends. + int cpLength = spanOneBack(spanSet, s, pos); + if (cpLength > 0) { + return pos; // There is a set element at pos. + } + + // Try to match the strings at pos. + for (i = 0; i < stringsLength; ++i) { + // Use spanLengths rather than a spanLengths pointer because + // it is easier and we only need to know whether the string is irrelevant + // which is the same in either array. + if (spanLengths[i] == ALL_CP_CONTAINED) { + continue; // Irrelevant string. + } + String string = strings.get(i); + + int length16 = string.length(); + if (length16 <= pos && matches16CPB(s, pos - length16, length, string, length16)) { + return pos; // There is a set element at pos. + } + } + + // The span(while not contained) ended on a string start/end which is + // not in the original set. Skip this code point and continue. + // cpLength<0 + pos += cpLength; + } while (pos != 0); + return 0; // Reached the start of the string. + } + + static short makeSpanLengthByte(int spanLength) { + // 0xfe==UnicodeSetStringSpan::LONG_SPAN + return spanLength < LONG_SPAN ? (short) spanLength : LONG_SPAN; + } + + // Compare strings without any argument checks. Requires length>0. + private static boolean matches16(CharSequence s, int start, final String t, int length) { + int end = start + length; + while (length-- > 0) { + if (s.charAt(--end) != t.charAt(length)) { + return false; + } + } + return true; + } + + /** + * Compare 16-bit Unicode strings (which may be malformed UTF-16) at code point + * boundaries. That is, each edge of a match must not be in the middle of a + * surrogate pair. + * + * @param s The string to match in. + * @param start The start index of s. + * @param limit The limit of the subsequence of s being spanned. + * @param t The substring to be matched in s. + * @param tlength The length of t. + */ + static boolean matches16CPB(CharSequence s, int start, int limit, final String t, int tlength) { + return matches16(s, start, t, tlength) + && !(0 < start && Character.isHighSurrogate(s.charAt(start - 1)) + && Character.isLowSurrogate(s.charAt(start))) + && !((start + tlength) < limit && Character.isHighSurrogate(s.charAt(start + tlength - 1)) + && Character.isLowSurrogate(s.charAt(start + tlength))); + } + + /** + * Does the set contain the next code point? If so, return its length; otherwise + * return its negative length. + */ + static int spanOne(final UnicodeSet set, CharSequence s, int start, int length) { + char c = s.charAt(start); + if (c >= 0xd800 && c <= 0xdbff && length >= 2) { + char c2 = s.charAt(start + 1); + if (UTF16.isTrailSurrogate(c2)) { + int supplementary = UCharacterProperty.getRawSupplementary(c, c2); + return set.contains(supplementary) ? 2 : -2; + } + } + return set.contains(c) ? 1 : -1; + } + + static int spanOneBack(final UnicodeSet set, CharSequence s, int length) { + char c = s.charAt(length - 1); + if (c >= 0xdc00 && c <= 0xdfff && length >= 2) { + char c2 = s.charAt(length - 2); + if (UTF16.isLeadSurrogate(c2)) { + int supplementary = UCharacterProperty.getRawSupplementary(c2, c); + return set.contains(supplementary) ? 2 : -2; + } + } + return set.contains(c) ? 1 : -1; + } + + /** + * Helper class for UnicodeSetStringSpan. + * + *

+ * List of offsets from the current position from where to try matching a code + * point or a string. Stores offsets rather than indexes to simplify the code + * and use the same list for both increments (in span()) and decrements (in + * spanBack()). + * + *

+ * Assumption: The maximum offset is limited, and the offsets that are stored at + * any one time are relatively dense, that is, there are normally no gaps of + * hundreds or thousands of offset values. + * + *

+ * This class optionally also tracks the minimum non-negative count for each + * position, intended to count the smallest number of elements of any path + * leading to that position. + * + *

+ * The implementation uses a circular buffer of count integers, each indicating + * whether the corresponding offset is in the list, and its path element count. + * This avoids inserting into a sorted list of offsets (or absolute indexes) and + * physically moving part of the list. + * + *

+ * Note: In principle, the caller should setMaxLength() to the maximum of the + * max string length and U16_LENGTH/U8_LENGTH to account for "long" single code + * points. + * + *

+ * Note: An earlier version did not track counts and stored only byte flags. + * With boolean flags, if maxLength were guaranteed to be no more than 32 or 64, + * the list could be stored as bit flags in a single integer. Rather than + * handling a circular buffer with a start list index, the integer would simply + * be shifted when lower offsets are removed. UnicodeSet does not have a limit + * on the lengths of strings. + */ + private static final class OffsetList { + private int[] list; + private int length; + private int start; + + public OffsetList() { + list = new int[16]; // default size + } + + public void setMaxLength(int maxLength) { + if (maxLength > list.length) { + list = new int[maxLength]; + } + clear(); + } + + public void clear() { + for (int i = list.length; i-- > 0;) { + list[i] = 0; + } + start = length = 0; + } + + public boolean isEmpty() { + return (length == 0); + } + + /** + * Reduces all stored offsets by delta, used when the current position moves by + * delta. There must not be any offsets lower than delta. If there is an offset + * equal to delta, it is removed. + * + * @param delta [1..maxLength] + */ + public void shift(int delta) { + int i = start + delta; + if (i >= list.length) { + i -= list.length; + } + if (list[i] != 0) { + list[i] = 0; + --length; + } + start = i; + } + + /** + * Adds an offset. The list must not contain it yet. + * + * @param offset [1..maxLength] + */ + public void addOffset(int offset) { + int i = start + offset; + if (i >= list.length) { + i -= list.length; + } + assert list[i] == 0; + list[i] = 1; + ++length; + } + + /** + * Adds an offset and updates its count. The list may already contain the + * offset. + * + * @param offset [1..maxLength] + */ + public void addOffsetAndCount(int offset, int count) { + assert count > 0; + int i = start + offset; + if (i >= list.length) { + i -= list.length; + } + if (list[i] == 0) { + list[i] = count; + ++length; + } else if (count < list[i]) { + list[i] = count; + } + } + + /** + * @param offset [1..maxLength] + */ + public boolean containsOffset(int offset) { + int i = start + offset; + if (i >= list.length) { + i -= list.length; + } + return list[i] != 0; + } + + /** + * @param offset [1..maxLength] + */ + public boolean hasCountAtOffset(int offset, int count) { + int i = start + offset; + if (i >= list.length) { + i -= list.length; + } + int oldCount = list[i]; + return oldCount != 0 && oldCount <= count; + } + + /** + * Finds the lowest stored offset from a non-empty list, removes it, and reduces + * all other offsets by this minimum. + * + * @return min=[1..maxLength] + */ + public int popMinimum(OutputInt outCount) { + // Look for the next offset in list[start+1..list.length-1]. + int i = start, result; + while (++i < list.length) { + int count = list[i]; + if (count != 0) { + list[i] = 0; + --length; + result = i - start; + start = i; + if (outCount != null) { + outCount.value = count; + } + return result; + } + } + // i==list.length + + // Wrap around and look for the next offset in list[0..start]. + // Since the list is not empty, there will be one. + result = list.length - start; + i = 0; + int count; + while ((count = list[i]) == 0) { + ++i; + } + list[i] = 0; + --length; + start = i; + if (outCount != null) { + outCount.value = count; + } + return result + i; + } + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/Utility.java b/src/main/java/jdk_internal/bidi/icu/impl/Utility.java new file mode 100755 index 00000000..74d0852d --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/Utility.java @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + ******************************************************************************* + * Copyright (C) 1996-2011, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.impl; + +import java.io.IOException; +import java.util.Locale; + +import jdk_internal.bidi.icu.lang.UCharacter; +import jdk_internal.bidi.icu.text.UTF16; + +public final class Utility { + + /** + * Convert characters outside the range U+0020 to U+007F to Unicode escapes, and + * convert backslash to a double backslash. + */ + public static final String escape(String s) { + StringBuilder buf = new StringBuilder(); + for (int i = 0; i < s.length();) { + int c = Character.codePointAt(s, i); + i += UTF16.getCharCount(c); + if (c >= ' ' && c <= 0x007F) { + if (c == '\\') { + buf.append("\\\\"); // That is, "\\" + } else { + buf.append((char) c); + } + } else { + boolean four = c <= 0xFFFF; + buf.append(four ? "\\u" : "\\U"); + buf.append(hex(c, four ? 4 : 8)); + } + } + return buf.toString(); + } + + /* This map must be in ASCENDING ORDER OF THE ESCAPE CODE */ + private static final char[] UNESCAPE_MAP = { + /* " 0x22, 0x22 */ + /* ' 0x27, 0x27 */ + /* ? 0x3F, 0x3F */ + /* \ 0x5C, 0x5C */ + /* a */ 0x61, 0x07, /* b */ 0x62, 0x08, /* e */ 0x65, 0x1b, /* f */ 0x66, 0x0c, /* n */ 0x6E, 0x0a, + /* r */ 0x72, 0x0d, /* t */ 0x74, 0x09, /* v */ 0x76, 0x0b }; + + /** + * Convert an escape to a 32-bit code point value. We attempt to parallel the + * icu4c unescapeAt() function. + * + * @param offset16 an array containing offset to the character after + * the backslash. Upon return offset16[0] will be updated to + * point after the escape sequence. + * @return character value from 0 to 10FFFF, or -1 on error. + */ + public static int unescapeAt(String s, int[] offset16) { + int c; + int result = 0; + int n = 0; + int minDig = 0; + int maxDig = 0; + int bitsPerDigit = 4; + int dig; + int i; + boolean braces = false; + + /* Check that offset is in range */ + int offset = offset16[0]; + int length = s.length(); + if (offset < 0 || offset >= length) { + return -1; + } + + /* Fetch first UChar after '\\' */ + c = Character.codePointAt(s, offset); + offset += UTF16.getCharCount(c); + + /* Convert hexadecimal and octal escapes */ + switch (c) { + case 'u': + minDig = maxDig = 4; + break; + case 'U': + minDig = maxDig = 8; + break; + case 'x': + minDig = 1; + if (offset < length && UTF16.charAt(s, offset) == 0x7B /* { */) { + ++offset; + braces = true; + maxDig = 8; + } else { + maxDig = 2; + } + break; + default: + dig = UCharacter.digit(c, 8); + if (dig >= 0) { + minDig = 1; + maxDig = 3; + n = 1; /* Already have first octal digit */ + bitsPerDigit = 3; + result = dig; + } + break; + } + if (minDig != 0) { + while (offset < length && n < maxDig) { + c = UTF16.charAt(s, offset); + dig = UCharacter.digit(c, (bitsPerDigit == 3) ? 8 : 16); + if (dig < 0) { + break; + } + result = (result << bitsPerDigit) | dig; + offset += UTF16.getCharCount(c); + ++n; + } + if (n < minDig) { + return -1; + } + if (braces) { + if (c != 0x7D /* } */) { + return -1; + } + ++offset; + } + if (result < 0 || result >= 0x110000) { + return -1; + } + // If an escape sequence specifies a lead surrogate, see + // if there is a trail surrogate after it, either as an + // escape or as a literal. If so, join them up into a + // supplementary. + if (offset < length && UTF16.isLeadSurrogate((char) result)) { + int ahead = offset + 1; + c = s.charAt(offset); // [sic] get 16-bit code unit + if (c == '\\' && ahead < length) { + int o[] = new int[] { ahead }; + c = unescapeAt(s, o); + ahead = o[0]; + } + if (UTF16.isTrailSurrogate((char) c)) { + offset = ahead; + result = UCharacterProperty.getRawSupplementary((char) result, (char) c); + } + } + offset16[0] = offset; + return result; + } + + /* Convert C-style escapes in table */ + for (i = 0; i < UNESCAPE_MAP.length; i += 2) { + if (c == UNESCAPE_MAP[i]) { + offset16[0] = offset; + return UNESCAPE_MAP[i + 1]; + } else if (c < UNESCAPE_MAP[i]) { + break; + } + } + + /* Map \cX to control-X: X & 0x1F */ + if (c == 'c' && offset < length) { + c = UTF16.charAt(s, offset); + offset16[0] = offset + UTF16.getCharCount(c); + return 0x1F & c; + } + + /* + * If no special forms are recognized, then consider the backslash to + * generically escape the next character. + */ + offset16[0] = offset; + return c; + } + + /** + * Supplies a zero-padded hex representation of an integer (without 0x) + */ + public static String hex(long i, int places) { + if (i == Long.MIN_VALUE) + return "-8000000000000000"; + boolean negative = i < 0; + if (negative) { + i = -i; + } + String result = Long.toString(i, 16).toUpperCase(Locale.ENGLISH); + if (result.length() < places) { + result = "0000000000000000".substring(result.length(), places) + result; + } + if (negative) { + return '-' + result; + } + return result; + } + + static final char DIGITS[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; + + /** + * Return true if the character is NOT printable ASCII. The tab, newline and + * linefeed characters are considered unprintable. + */ + public static boolean isUnprintable(int c) { + // 0x20 = 32 and 0x7E = 126 + return !(c >= 0x20 && c <= 0x7E); + } + + /** + * Escape unprintable characters using uxxxx notation for U+0000 to + * U+FFFF and Uxxxxxxxx for U+10000 and above. If the character is + * printable ASCII, then do nothing and return FALSE. Otherwise, append the + * escaped notation and return TRUE. + */ + public static boolean escapeUnprintable(T result, int c) { + try { + if (isUnprintable(c)) { + result.append('\\'); + if ((c & ~0xFFFF) != 0) { + result.append('U'); + result.append(DIGITS[0xF & (c >> 28)]); + result.append(DIGITS[0xF & (c >> 24)]); + result.append(DIGITS[0xF & (c >> 20)]); + result.append(DIGITS[0xF & (c >> 16)]); + } else { + result.append('u'); + } + result.append(DIGITS[0xF & (c >> 12)]); + result.append(DIGITS[0xF & (c >> 8)]); + result.append(DIGITS[0xF & (c >> 4)]); + result.append(DIGITS[0xF & c]); + return true; + } + return false; + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/lang/UCharacter.java b/src/main/java/jdk_internal/bidi/icu/lang/UCharacter.java new file mode 100755 index 00000000..3c0fce0e --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/lang/UCharacter.java @@ -0,0 +1,562 @@ +/* + * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** +******************************************************************************* +* Copyright (C) 1996-2014, International Business Machines Corporation and +* others. All Rights Reserved. +******************************************************************************* +*/ + +package jdk_internal.bidi.icu.lang; + +import jdk_internal.bidi.icu.impl.UBiDiProps; +import jdk_internal.bidi.icu.impl.UCharacterProperty; +import jdk_internal.bidi.icu.text.Normalizer2; +import jdk_internal.bidi.icu.text.UTF16; +import jdk_internal.bidi.icu.util.VersionInfo; + +/** + *

+ * The UCharacter class provides extensions to the + * + * java.lang.Character class. These extensions provide support for more + * Unicode properties and together with the UTF16 + * class, provide support for supplementary characters (those with code points + * above U+FFFF). Each ICU release supports the latest version of Unicode + * available at that time. + * + *

+ * Code points are represented in these API using ints. While it would be more + * convenient in Java to have a separate primitive datatype for them, ints + * suffice in the meantime. + * + *

+ * To use this class please add the jar file name icu4j.jar to the class path, + * since it contains data files which supply the information used by this + * file.
+ * E.g. In Windows
+ * set CLASSPATH=%CLASSPATH%;$JAR_FILE_PATH/ucharacter.jar.
+ * Otherwise, another method would be to copy the files uprops.dat and + * unames.icu from the icu4j source subdirectory + * $ICU4J_SRC/src/com.ibm.icu.impl.data to your class directory + * $ICU4J_CLASS/com.ibm.icu.impl.data. + * + *

+ * Aside from the additions for UTF-16 support, and the updated Unicode + * properties, the main differences between UCharacter and Character are: + *

    + *
  • UCharacter is not designed to be a char wrapper and does not have APIs to + * which involves management of that single char.
    + * These include: + *
      + *
    • char charValue(), + *
    • int compareTo(java.lang.Character, java.lang.Character), etc. + *
    + *
  • UCharacter does not include Character APIs that are deprecated, nor does + * it include the Java-specific character information, such as boolean + * isJavaIdentifierPart(char ch). + *
  • Character maps characters 'A' - 'Z' and 'a' - 'z' to the numeric values + * '10' - '35'. UCharacter also does this in digit and getNumericValue, to + * adhere to the java semantics of these methods. New methods unicodeDigit, and + * getUnicodeNumericValue do not treat the above code points as having numeric + * values. This is a semantic change from ICU4J 1.3.1. + *
+ *

+ * Further detail on differences can be determined using the program + * com.ibm.icu.dev.test.lang.UCharacterCompare + *

+ *

+ * In addition to Java compatibility functions, which calculate derived + * properties, this API provides low-level access to the Unicode Character + * Database. + *

+ *

+ * Unicode assigns each code point (not just assigned character) values for many + * properties. Most of them are simple boolean flags, or constants from a small + * enumerated list. For some properties, values are strings or other relatively + * more complex types. + *

+ *

+ * For more information see "About the + * Unicode Character Database" (http://www.unicode.org/ucd/) and the + * ICU User Guide + * chapter on Properties + * (http://www.icu-project.org/userguide/properties.html). + *

+ *

+ * There are also functions that provide easy migration from C/POSIX functions + * like isblank(). Their use is generally discouraged because the C/POSIX + * standards do not define their semantics beyond the ASCII range, which means + * that different implementations exhibit very different behavior. Instead, + * Unicode properties should be used directly. + *

+ *

+ * There are also only a few, broad C/POSIX character classes, and they tend to + * be used for conflicting purposes. For example, the "isalpha()" class is + * sometimes used to determine word boundaries, while a more sophisticated + * approach would at least distinguish initial letters from continuation + * characters (the latter including combining marks). (In ICU, BreakIterator is + * the most sophisticated API for word boundaries.) Another example: There is no + * "istitle()" class for titlecase characters. + *

+ *

+ * ICU 3.4 and later provides API access for all twelve C/POSIX character + * classes. ICU implements them according to the Standard Recommendations in + * Annex C: Compatibility Properties of UTS #18 Unicode Regular Expressions + * (http://www.unicode.org/reports/tr18/#Compatibility_Properties). + *

+ *

+ * API access for C/POSIX character classes is as follows: + * + *

{@code
+ * - alpha:     isUAlphabetic(c) or hasBinaryProperty(c, UProperty.ALPHABETIC)
+ * - lower:     isULowercase(c) or hasBinaryProperty(c, UProperty.LOWERCASE)
+ * - upper:     isUUppercase(c) or hasBinaryProperty(c, UProperty.UPPERCASE)
+ * - punct:     ((1<
+ * 

+ *

+ * The C/POSIX character classes are also available in UnicodeSet patterns, + * using patterns like [:graph:] or \p{graph}. + *

+ * + * There are several ICU (and Java) whitespace functions. Comparison: + *
    + *
  • isUWhiteSpace=UCHAR_WHITE_SPACE: Unicode White_Space property; most of + * general categories "Z" (separators) + most whitespace ISO controls (including + * no-break spaces, but excluding IS1..IS4 and ZWSP) + *
  • isWhitespace: Java isWhitespace; Z + whitespace ISO controls but + * excluding no-break spaces + *
  • isSpaceChar: just Z (including no-break spaces) + *
+ *

+ *

+ * This class is not subclassable. + *

+ * + * @author Syn Wee Quek + * @stable ICU 2.1 + * @see com.ibm.icu.lang.UCharacterEnums + */ + +public final class UCharacter { + + /** + * Joining Group constants. + * + * @see UProperty#JOINING_GROUP + * @stable ICU 2.4 + */ + public static interface JoiningGroup { + /** + * @stable ICU 2.4 + */ + public static final int NO_JOINING_GROUP = 0; + } + + /** + * Numeric Type constants. + * + * @see UProperty#NUMERIC_TYPE + * @stable ICU 2.4 + */ + public static interface NumericType { + /** + * @stable ICU 2.4 + */ + public static final int NONE = 0; + /** + * @stable ICU 2.4 + */ + public static final int DECIMAL = 1; + /** + * @stable ICU 2.4 + */ + public static final int DIGIT = 2; + /** + * @stable ICU 2.4 + */ + public static final int NUMERIC = 3; + /** + * @stable ICU 2.4 + */ + public static final int COUNT = 4; + } + + /** + * Hangul Syllable Type constants. + * + * @see UProperty#HANGUL_SYLLABLE_TYPE + * @stable ICU 2.6 + */ + public static interface HangulSyllableType { + /** + * @stable ICU 2.6 + */ + public static final int NOT_APPLICABLE = 0; /* [NA] */ /* See note !! */ + /** + * @stable ICU 2.6 + */ + public static final int LEADING_JAMO = 1; /* [L] */ + /** + * @stable ICU 2.6 + */ + public static final int VOWEL_JAMO = 2; /* [V] */ + /** + * @stable ICU 2.6 + */ + public static final int TRAILING_JAMO = 3; /* [T] */ + /** + * @stable ICU 2.6 + */ + public static final int LV_SYLLABLE = 4; /* [LV] */ + /** + * @stable ICU 2.6 + */ + public static final int LVT_SYLLABLE = 5; /* [LVT] */ + /** + * @stable ICU 2.6 + */ + public static final int COUNT = 6; + } + + // public data members ----------------------------------------------- + + /** + * The lowest Unicode code point value. + * + * @stable ICU 2.1 + */ + public static final int MIN_VALUE = UTF16.CODEPOINT_MIN_VALUE; + + /** + * The highest Unicode code point value (scalar value) according to the Unicode + * Standard. This is a 21-bit value (21 bits, rounded up).
+ * Up-to-date Unicode implementation of java.lang.Character.MAX_VALUE + * + * @stable ICU 2.1 + */ + public static final int MAX_VALUE = UTF16.CODEPOINT_MAX_VALUE; + + // public methods ---------------------------------------------------- + + /** + * Returns the numeric value of a decimal digit code point.
+ * This method observes the semantics of + * java.lang.Character.digit(). Note that this will return positive + * values for code points for which isDigit returns false, just like + * java.lang.Character.
+ * Semantic Change: In release 1.3.1 and prior, this did not treat the + * European letters as having a digit value, and also treated numeric letters + * and other numbers as digits. This has been changed to conform to the java + * semantics.
+ * A code point is a valid digit if and only if: + *
    + *
  • ch is a decimal digit or one of the european letters, and + *
  • the value of ch is less than the specified radix. + *
+ * + * @param ch the code point to query + * @param radix the radix + * @return the numeric value represented by the code point in the specified + * radix, or -1 if the code point is not a decimal digit or if its value + * is too large for the radix + * @stable ICU 2.1 + */ + public static int digit(int ch, int radix) { + if (2 <= radix && radix <= 36) { + int value = digit(ch); + if (value < 0) { + // ch is not a decimal digit, try latin letters + value = UCharacterProperty.getEuropeanDigit(ch); + } + return (value < radix) ? value : -1; + } else { + return -1; // invalid radix + } + } + + /** + * Returns the numeric value of a decimal digit code point.
+ * This is a convenience overload of digit(int, int) that provides + * a decimal radix.
+ * Semantic Change: In release 1.3.1 and prior, this treated numeric + * letters and other numbers as digits. This has been changed to conform to the + * java semantics. + * + * @param ch the code point to query + * @return the numeric value represented by the code point, or -1 if the code + * point is not a decimal digit or if its value is too large for a + * decimal radix + * @stable ICU 2.1 + */ + public static int digit(int ch) { + return UCharacterProperty.INSTANCE.digit(ch); + } + + /** + * Returns a value indicating a code point's Unicode category. Up-to-date + * Unicode implementation of java.lang.Character.getType() except for the above + * mentioned code points that had their category changed.
+ * Return results are constants from the interface + * UCharacterCategory
+ * NOTE: the UCharacterCategory values are not compatible with + * those returned by java.lang.Character.getType. UCharacterCategory values + * match the ones used in ICU4C, while java.lang.Character type values, though + * similar, skip the value 17. + *

+ * + * @param ch code point whose type is to be determined + * @return category which is a value of UCharacterCategory + * @stable ICU 2.1 + */ + public static int getType(int ch) { + return UCharacterProperty.INSTANCE.getType(ch); + } + + /** + * Returns the Bidirection property of a code point. For example, 0x0041 (letter + * A) has the LEFT_TO_RIGHT directional property.
+ * Result returned belongs to the interface + * UCharacterDirection + * + * @param ch the code point to be determined its direction + * @return direction constant from UCharacterDirection. + * @stable ICU 2.1 + */ + public static int getDirection(int ch) { + return UBiDiProps.INSTANCE.getClass(ch); + } + + /** + * Maps the specified code point to a "mirror-image" code point. For code points + * with the "mirrored" property, implementations sometimes need a "poor man's" + * mapping to another code point such that the default glyph may serve as the + * mirror-image of the default glyph of the specified code point.
+ * This is useful for text conversion to and from codepages with visual order, + * and for displays without glyph selection capabilities. + * + * @param ch code point whose mirror is to be retrieved + * @return another code point that may serve as a mirror-image substitute, or ch + * itself if there is no such mapping or ch does not have the "mirrored" + * property + * @stable ICU 2.1 + */ + public static int getMirror(int ch) { + return UBiDiProps.INSTANCE.getMirror(ch); + } + + /** + * Maps the specified character to its paired bracket character. For + * Bidi_Paired_Bracket_Type!=None, this is the same as getMirror(int). Otherwise + * c itself is returned. See http://www.unicode.org/reports/tr9/ + * + * @param c the code point to be mapped + * @return the paired bracket code point, or c itself if there is no such + * mapping (Bidi_Paired_Bracket_Type=None) + * + * @see UProperty#BIDI_PAIRED_BRACKET + * @see UProperty#BIDI_PAIRED_BRACKET_TYPE + * @see #getMirror(int) + * @stable ICU 52 + */ + public static int getBidiPairedBracket(int c) { + return UBiDiProps.INSTANCE.getPairedBracket(c); + } + + /** + * Returns the combining class of the argument codepoint + * + * @param ch code point whose combining is to be retrieved + * @return the combining class of the codepoint + * @stable ICU 2.1 + */ + public static int getCombiningClass(int ch) { + return Normalizer2.getNFDInstance().getCombiningClass(ch); + } + + /** + * Returns the version of Unicode data used. + * + * @return the unicode version number used + * @stable ICU 2.1 + */ + public static VersionInfo getUnicodeVersion() { + return UCharacterProperty.INSTANCE.m_unicodeVersion_; + } + + /** + * Returns a code point corresponding to the two UTF16 characters. + * + * @param lead the lead char + * @param trail the trail char + * @return code point if surrogate characters are valid. + * @exception IllegalArgumentException thrown when argument characters do not + * form a valid codepoint + * @stable ICU 2.1 + */ + public static int getCodePoint(char lead, char trail) { + if (UTF16.isLeadSurrogate(lead) && UTF16.isTrailSurrogate(trail)) { + return UCharacterProperty.getRawSupplementary(lead, trail); + } + throw new IllegalArgumentException("Illegal surrogate characters"); + } + + /** + * Returns the "age" of the code point. + *

+ *

+ * The "age" is the Unicode version when the code point was first designated (as + * a non-character or for Private Use) or assigned a character. + *

+ * This can be useful to avoid emitting code points to receiving processes that + * do not accept newer characters. + *

+ *

+ * The data is from the UCD file DerivedAge.txt. + *

+ * + * @param ch The code point. + * @return the Unicode version number + * @stable ICU 2.6 + */ + public static VersionInfo getAge(int ch) { + if (ch < MIN_VALUE || ch > MAX_VALUE) { + throw new IllegalArgumentException("Codepoint out of bounds"); + } + return UCharacterProperty.INSTANCE.getAge(ch); + } + + /** + * Returns the property value for an Unicode property type of a code point. Also + * returns binary and mask property values. + *

+ *

+ * Unicode, especially in version 3.2, defines many more properties than the + * original set in UnicodeData.txt. + *

+ *

+ * The properties APIs are intended to reflect Unicode properties as defined in + * the Unicode Character Database (UCD) and Unicode Technical Reports (UTR). For + * details about the properties see http://www.unicode.org/. + *

+ *

+ * For names of Unicode properties see the UCD file PropertyAliases.txt. + *

+ * + *
+	 * Sample usage:
+	 * int ea = UCharacter.getIntPropertyValue(c, UProperty.EAST_ASIAN_WIDTH);
+	 * int ideo = UCharacter.getIntPropertyValue(c, UProperty.IDEOGRAPHIC);
+	 * boolean b = (ideo == 1) ? true : false;
+	 * 
+ * + * @param ch code point to test. + * @param type UProperty selector constant, identifies which binary property to + * check. Must be UProperty.BINARY_START <= type < + * UProperty.BINARY_LIMIT or UProperty.INT_START <= type < + * UProperty.INT_LIMIT or UProperty.MASK_START <= type < + * UProperty.MASK_LIMIT. + * @return numeric value that is directly the property value or, for enumerated + * properties, corresponds to the numeric value of the enumerated + * constant of the respective property value enumeration type (cast to + * enum type if necessary). Returns 0 or 1 (for false / true) for binary + * Unicode properties. Returns a bit-mask for mask properties. Returns 0 + * if 'type' is out of bounds or if the Unicode version does not have + * data for the property at all, or not for this code point. + * @see UProperty + * @see #hasBinaryProperty + * @see #getIntPropertyMinValue + * @see #getIntPropertyMaxValue + * @see #getUnicodeVersion + * @stable ICU 2.4 + */ + // for BiDiBase.java + public static int getIntPropertyValue(int ch, int type) { + return UCharacterProperty.INSTANCE.getIntPropertyValue(ch, type); + } + + // private constructor ----------------------------------------------- + + /** + * Private constructor to prevent instantiation + */ + private UCharacter() { + } + + /* + * Copied from UCharacterEnums.java + */ + + /** + * Character type Mn + * + * @stable ICU 2.1 + */ + public static final byte NON_SPACING_MARK = 6; + /** + * Character type Me + * + * @stable ICU 2.1 + */ + public static final byte ENCLOSING_MARK = 7; + /** + * Character type Mc + * + * @stable ICU 2.1 + */ + public static final byte COMBINING_SPACING_MARK = 8; + /** + * Character type count + * + * @stable ICU 2.1 + */ + public static final byte CHAR_CATEGORY_COUNT = 30; + + /** + * Directional type R + * + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT = 1; + /** + * Directional type AL + * + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT_ARABIC = 13; +} diff --git a/src/main/java/jdk_internal/bidi/icu/lang/UCharacterDirection.java b/src/main/java/jdk_internal/bidi/icu/lang/UCharacterDirection.java new file mode 100755 index 00000000..7a3c8035 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/lang/UCharacterDirection.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* +/** +******************************************************************************* +* Copyright (C) 1996-2004, International Business Machines Corporation and * +* others. All Rights Reserved. * +******************************************************************************* +*/ +// CHANGELOG +// 2005-05-19 Edward Wang +// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/lang/UCharacterDirection.java +// - move from package com.ibm.icu.lang to package sun.net.idn +// + +package jdk_internal.bidi.icu.lang; + +/** + * Enumerated Unicode character linguistic direction constants. Used as return + * results from UCharacter + *

+ * This class is not subclassable + *

+ * + * @author Syn Wee Quek + * @stable ICU 2.1 + */ + +@SuppressWarnings("deprecation") +public final class UCharacterDirection implements UCharacterEnums.ECharacterDirection { + + // private constructor ========================================= + /// CLOVER:OFF + /** + * Private constructor to prevent initialisation + */ + private UCharacterDirection() { + } + /// CLOVER:ON + + /** + * Gets the name of the argument direction + * + * @param dir direction type to retrieve name + * @return directional name + * @stable ICU 2.1 + */ + public static String toString(int dir) { + switch (dir) { + case LEFT_TO_RIGHT: + return "Left-to-Right"; + case RIGHT_TO_LEFT: + return "Right-to-Left"; + case EUROPEAN_NUMBER: + return "European Number"; + case EUROPEAN_NUMBER_SEPARATOR: + return "European Number Separator"; + case EUROPEAN_NUMBER_TERMINATOR: + return "European Number Terminator"; + case ARABIC_NUMBER: + return "Arabic Number"; + case COMMON_NUMBER_SEPARATOR: + return "Common Number Separator"; + case BLOCK_SEPARATOR: + return "Paragraph Separator"; + case SEGMENT_SEPARATOR: + return "Segment Separator"; + case WHITE_SPACE_NEUTRAL: + return "Whitespace"; + case OTHER_NEUTRAL: + return "Other Neutrals"; + case LEFT_TO_RIGHT_EMBEDDING: + return "Left-to-Right Embedding"; + case LEFT_TO_RIGHT_OVERRIDE: + return "Left-to-Right Override"; + case RIGHT_TO_LEFT_ARABIC: + return "Right-to-Left Arabic"; + case RIGHT_TO_LEFT_EMBEDDING: + return "Right-to-Left Embedding"; + case RIGHT_TO_LEFT_OVERRIDE: + return "Right-to-Left Override"; + case POP_DIRECTIONAL_FORMAT: + return "Pop Directional Format"; + case DIR_NON_SPACING_MARK: + return "Non-Spacing Mark"; + case BOUNDARY_NEUTRAL: + return "Boundary Neutral"; + } + return "Unassigned"; + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/lang/UCharacterEnums.java b/src/main/java/jdk_internal/bidi/icu/lang/UCharacterEnums.java new file mode 100755 index 00000000..dd09e6f6 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/lang/UCharacterEnums.java @@ -0,0 +1,666 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* +/** + ******************************************************************************* + * Copyright (C) 2004, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ +// CHANGELOG +// 2005-05-19 Edward Wang +// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/lang/UCharacterEnums.java +// - move from package com.ibm.icu.lang to package sun.net.idn +// +// 2011-09-06 Kurchi Subhra Hazra +// - Added @Deprecated tag to the following: +// - class UCharacterEnums +// - interfaces ECharacterCategory, ECharacterDirection +// - fields INITIAL_QUOTE_PUNCTUATION, FINAL_QUOTE_PUNCTUATION, +// DIRECTIONALITY_LEFT_TO_RIGHT, DIRECTIONALITY_RIGHT_TO_LEFT, +// DIRECTIONALITY_EUROPEAN_NUMBER, DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR +// DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR, DIRECTIONALITY_ARABIC_NUMBER, +// DIRECTIONALITY_COMMON_NUMBER_SEPARATOR, DIRECTIONALITY_PARAGRAPH_SEPARATOR, +// DIRECTIONALITY_SEGMENT_SEPARATOR, DIRECTIONALITY_WHITESPACE, +// DIRECTIONALITY_OTHER_NEUTRALS, DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING, +// DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE, DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC, +// DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING, DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE, +// DIRECTIONALITY_POP_DIRECTIONAL_FORMAT, DIRECTIONALITY_NON_SPACING_MARK, +// DIRECTIONALITY_BOUNDARY_NEUTRAL, DIRECTIONALITY_UNDEFINED +// + +package jdk_internal.bidi.icu.lang; + +/** + * A container for the different 'enumerated types' used by UCharacter. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + +@Deprecated +class UCharacterEnums { + + /** This is just a namespace, it is not instantiatable. */ + private UCharacterEnums() { + }; + + /** + * 'Enum' for the CharacterCategory constants. These constants are compatible in + * name but not in value with those defined in + * java.lang.Character. + * + * @see UCharacterCategory + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static interface ECharacterCategory { + /** + * Unassigned character type + * + * @stable ICU 2.1 + */ + public static final int UNASSIGNED = 0; + + /** + * Character type Cn Not Assigned (no characters in [UnicodeData.txt] have this + * property) + * + * @stable ICU 2.6 + */ + public static final int GENERAL_OTHER_TYPES = 0; + + /** + * Character type Lu + * + * @stable ICU 2.1 + */ + public static final int UPPERCASE_LETTER = 1; + + /** + * Character type Ll + * + * @stable ICU 2.1 + */ + public static final int LOWERCASE_LETTER = 2; + + /** + * Character type Lt + * + * @stable ICU 2.1 + */ + + public static final int TITLECASE_LETTER = 3; + + /** + * Character type Lm + * + * @stable ICU 2.1 + */ + public static final int MODIFIER_LETTER = 4; + + /** + * Character type Lo + * + * @stable ICU 2.1 + */ + public static final int OTHER_LETTER = 5; + + /** + * Character type Mn + * + * @stable ICU 2.1 + */ + public static final int NON_SPACING_MARK = 6; + + /** + * Character type Me + * + * @stable ICU 2.1 + */ + public static final int ENCLOSING_MARK = 7; + + /** + * Character type Mc + * + * @stable ICU 2.1 + */ + public static final int COMBINING_SPACING_MARK = 8; + + /** + * Character type Nd + * + * @stable ICU 2.1 + */ + public static final int DECIMAL_DIGIT_NUMBER = 9; + + /** + * Character type Nl + * + * @stable ICU 2.1 + */ + public static final int LETTER_NUMBER = 10; + + /** + * Character type No + * + * @stable ICU 2.1 + */ + public static final int OTHER_NUMBER = 11; + + /** + * Character type Zs + * + * @stable ICU 2.1 + */ + public static final int SPACE_SEPARATOR = 12; + + /** + * Character type Zl + * + * @stable ICU 2.1 + */ + public static final int LINE_SEPARATOR = 13; + + /** + * Character type Zp + * + * @stable ICU 2.1 + */ + public static final int PARAGRAPH_SEPARATOR = 14; + + /** + * Character type Cc + * + * @stable ICU 2.1 + */ + public static final int CONTROL = 15; + + /** + * Character type Cf + * + * @stable ICU 2.1 + */ + public static final int FORMAT = 16; + + /** + * Character type Co + * + * @stable ICU 2.1 + */ + public static final int PRIVATE_USE = 17; + + /** + * Character type Cs + * + * @stable ICU 2.1 + */ + public static final int SURROGATE = 18; + + /** + * Character type Pd + * + * @stable ICU 2.1 + */ + public static final int DASH_PUNCTUATION = 19; + + /** + * Character type Ps + * + * @stable ICU 2.1 + */ + public static final int START_PUNCTUATION = 20; + + /** + * Character type Pe + * + * @stable ICU 2.1 + */ + public static final int END_PUNCTUATION = 21; + + /** + * Character type Pc + * + * @stable ICU 2.1 + */ + public static final int CONNECTOR_PUNCTUATION = 22; + + /** + * Character type Po + * + * @stable ICU 2.1 + */ + public static final int OTHER_PUNCTUATION = 23; + + /** + * Character type Sm + * + * @stable ICU 2.1 + */ + public static final int MATH_SYMBOL = 24; + + /** + * Character type Sc + * + * @stable ICU 2.1 + */ + public static final int CURRENCY_SYMBOL = 25; + + /** + * Character type Sk + * + * @stable ICU 2.1 + */ + public static final int MODIFIER_SYMBOL = 26; + + /** + * Character type So + * + * @stable ICU 2.1 + */ + public static final int OTHER_SYMBOL = 27; + + /** + * Character type Pi + * + * @see #INITIAL_QUOTE_PUNCTUATION + * @stable ICU 2.1 + */ + public static final int INITIAL_PUNCTUATION = 28; + + /** + * Character type Pi This name is compatible with java.lang.Character's name for + * this type. + * + * @see #INITIAL_PUNCTUATION + * @draft ICU 2.8 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final int INITIAL_QUOTE_PUNCTUATION = 28; + + /** + * Character type Pf + * + * @see #FINAL_QUOTE_PUNCTUATION + * @stable ICU 2.1 + */ + public static final int FINAL_PUNCTUATION = 29; + + /** + * Character type Pf This name is compatible with java.lang.Character's name for + * this type. + * + * @see #FINAL_PUNCTUATION + * @draft ICU 2.8 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final int FINAL_QUOTE_PUNCTUATION = 29; + + /** + * Character type count + * + * @stable ICU 2.1 + */ + public static final int CHAR_CATEGORY_COUNT = 30; + } + + /** + * 'Enum' for the CharacterDirection constants. There are two sets of names, + * those used in ICU, and those used in the JDK. The JDK constants are + * compatible in name but not in value with those defined in + * java.lang.Character. + * + * @see UCharacterDirection + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + + @Deprecated + public static interface ECharacterDirection { + /** + * Directional type L + * + * @stable ICU 2.1 + */ + public static final int LEFT_TO_RIGHT = 0; + + /** + * JDK-compatible synonum for LEFT_TO_RIGHT. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT = (byte) LEFT_TO_RIGHT; + + /** + * Directional type R + * + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT = 1; + + /** + * JDK-compatible synonum for RIGHT_TO_LEFT. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT = (byte) RIGHT_TO_LEFT; + + /** + * Directional type EN + * + * @stable ICU 2.1 + */ + public static final int EUROPEAN_NUMBER = 2; + + /** + * JDK-compatible synonum for EUROPEAN_NUMBER. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER = (byte) EUROPEAN_NUMBER; + + /** + * Directional type ES + * + * @stable ICU 2.1 + */ + public static final int EUROPEAN_NUMBER_SEPARATOR = 3; + + /** + * JDK-compatible synonum for EUROPEAN_NUMBER_SEPARATOR. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR = (byte) EUROPEAN_NUMBER_SEPARATOR; + + /** + * Directional type ET + * + * @stable ICU 2.1 + */ + public static final int EUROPEAN_NUMBER_TERMINATOR = 4; + + /** + * JDK-compatible synonum for EUROPEAN_NUMBER_TERMINATOR. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR = (byte) EUROPEAN_NUMBER_TERMINATOR; + + /** + * Directional type AN + * + * @stable ICU 2.1 + */ + public static final int ARABIC_NUMBER = 5; + + /** + * JDK-compatible synonum for ARABIC_NUMBER. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_ARABIC_NUMBER = (byte) ARABIC_NUMBER; + + /** + * Directional type CS + * + * @stable ICU 2.1 + */ + public static final int COMMON_NUMBER_SEPARATOR = 6; + + /** + * JDK-compatible synonum for COMMON_NUMBER_SEPARATOR. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_COMMON_NUMBER_SEPARATOR = (byte) COMMON_NUMBER_SEPARATOR; + + /** + * Directional type B + * + * @stable ICU 2.1 + */ + public static final int BLOCK_SEPARATOR = 7; + + /** + * JDK-compatible synonum for BLOCK_SEPARATOR. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_PARAGRAPH_SEPARATOR = (byte) BLOCK_SEPARATOR; + + /** + * Directional type S + * + * @stable ICU 2.1 + */ + public static final int SEGMENT_SEPARATOR = 8; + + /** + * JDK-compatible synonum for SEGMENT_SEPARATOR. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_SEGMENT_SEPARATOR = (byte) SEGMENT_SEPARATOR; + + /** + * Directional type WS + * + * @stable ICU 2.1 + */ + public static final int WHITE_SPACE_NEUTRAL = 9; + + /** + * JDK-compatible synonum for WHITE_SPACE_NEUTRAL. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_WHITESPACE = (byte) WHITE_SPACE_NEUTRAL; + + /** + * Directional type ON + * + * @stable ICU 2.1 + */ + public static final int OTHER_NEUTRAL = 10; + + /** + * JDK-compatible synonum for OTHER_NEUTRAL. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_OTHER_NEUTRALS = (byte) OTHER_NEUTRAL; + + /** + * Directional type LRE + * + * @stable ICU 2.1 + */ + public static final int LEFT_TO_RIGHT_EMBEDDING = 11; + + /** + * JDK-compatible synonum for LEFT_TO_RIGHT_EMBEDDING. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING = (byte) LEFT_TO_RIGHT_EMBEDDING; + + /** + * Directional type LRO + * + * @stable ICU 2.1 + */ + public static final int LEFT_TO_RIGHT_OVERRIDE = 12; + + /** + * JDK-compatible synonum for LEFT_TO_RIGHT_OVERRIDE. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE = (byte) LEFT_TO_RIGHT_OVERRIDE; + + /** + * Directional type AL + * + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT_ARABIC = 13; + + /** + * JDK-compatible synonum for RIGHT_TO_LEFT_ARABIC. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC = (byte) RIGHT_TO_LEFT_ARABIC; + + /** + * Directional type RLE + * + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT_EMBEDDING = 14; + + /** + * JDK-compatible synonum for RIGHT_TO_LEFT_EMBEDDING. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING = (byte) RIGHT_TO_LEFT_EMBEDDING; + + /** + * Directional type RLO + * + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT_OVERRIDE = 15; + + /** + * JDK-compatible synonum for RIGHT_TO_LEFT_OVERRIDE. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE = (byte) RIGHT_TO_LEFT_OVERRIDE; + + /** + * Directional type PDF + * + * @stable ICU 2.1 + */ + public static final int POP_DIRECTIONAL_FORMAT = 16; + + /** + * JDK-compatible synonum for POP_DIRECTIONAL_FORMAT. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_POP_DIRECTIONAL_FORMAT = (byte) POP_DIRECTIONAL_FORMAT; + + /** + * Directional type NSM + * + * @stable ICU 2.1 + */ + public static final int DIR_NON_SPACING_MARK = 17; + + /** + * JDK-compatible synonum for DIR_NON_SPACING_MARK. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_NON_SPACING_MARK = (byte) DIR_NON_SPACING_MARK; + + /** + * Directional type BN + * + * @stable ICU 2.1 + */ + public static final int BOUNDARY_NEUTRAL = 18; + + /** + * JDK-compatible synonum for BOUNDARY_NEUTRAL. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = (byte) BOUNDARY_NEUTRAL; + + /** + * Number of directional types + * + * @stable ICU 2.1 + */ + public static final int CHAR_DIRECTION_COUNT = 19; + + /** + * Undefined bidirectional character type. Undefined char values + * have undefined directionality in the Unicode specification. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_UNDEFINED = -1; + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/BidiBase.java b/src/main/java/jdk_internal/bidi/icu/text/BidiBase.java new file mode 100755 index 00000000..ce33152a --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/BidiBase.java @@ -0,0 +1,4729 @@ +/* + * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* +******************************************************************************* +* Copyright (C) 2001-2014, International Business Machines +* Corporation and others. All Rights Reserved. +******************************************************************************* +*/ + +/* FOOD FOR THOUGHT: currently the reordering modes are a mixture of + * algorithm for direct BiDi, algorithm for inverse Bidi and the bizarre + * concept of RUNS_ONLY which is a double operation. + * It could be advantageous to divide this into 3 concepts: + * a) Operation: direct / inverse / RUNS_ONLY + * b) Direct algorithm: default / NUMBERS_SPECIAL / GROUP_NUMBERS_WITH_L + * c) Inverse algorithm: default / INVERSE_LIKE_DIRECT / NUMBERS_SPECIAL + * This would allow combinations not possible today like RUNS_ONLY with + * NUMBERS_SPECIAL. + * Also allow to set INSERT_MARKS for the direct step of RUNS_ONLY and + * REMOVE_CONTROLS for the inverse step. + * Not all combinations would be supported, and probably not all do make sense. + * This would need to document which ones are supported and what are the + * fallbacks for unsupported combinations. + */ + +package jdk_internal.bidi.icu.text; + +import java.lang.reflect.Array; +import java.util.Arrays; + +import jdk_internal.bidi.AttributedCharacterIterator; +import jdk_internal.bidi.Bidi; +import jdk_internal.bidi.NumericShaper; +import jdk_internal.bidi.TextAttribute; +import jdk_internal.bidi.icu.impl.UBiDiProps; +import jdk_internal.bidi.icu.lang.UCharacter; + +/** + * + *

Bidi algorithm for ICU

+ * + * This is an implementation of the Unicode Bidirectional Algorithm. The + * algorithm is defined in the + * Unicode Standard Annex #9: + * Unicode Bidirectional Algorithm. + *

+ * + * Note: Libraries that perform a bidirectional algorithm and reorder strings + * accordingly are sometimes called "Storage Layout Engines". ICU's Bidi and + * shaping (ArabicShaping) classes can be used at the core of such "Storage + * Layout Engines". + * + *

General remarks about the API:

+ * + * The "limit" of a sequence of characters is the position just after their last + * character, i.e., one more than that position. + *

+ * + * Some of the API methods provide access to "runs". Such a "run" is defined as + * a sequence of characters that are at the same embedding level after + * performing the Bidi algorithm. + * + *

Basic concept: paragraph

A piece of text can be divided into several + * paragraphs by characters with the Bidi class Block Separator. + * For handling of paragraphs, see: + *
    + *
  • {@link #countParagraphs} + *
  • {@link #getParaLevel} + *
  • {@link #getParagraph} + *
  • {@link #getParagraphByIndex} + *
+ * + *

Basic concept: text direction

The direction of a piece of text may + * be: + *
    + *
  • {@link #LTR} + *
  • {@link #RTL} + *
  • {@link #MIXED} + *
  • {@link #NEUTRAL} + *
+ * + *

Basic concept: levels

+ * + * Levels in this API represent embedding levels according to the Unicode + * Bidirectional Algorithm. Their low-order bit (even/odd value) indicates the + * visual direction. + *

+ * + * Levels can be abstract values when used for the paraLevel and + * embeddingLevels arguments of setPara(); there: + *

    + *
  • the high-order bit of an embeddingLevels[] value indicates + * whether the using application is specifying the level of a character to + * override whatever the Bidi implementation would resolve it to.
  • + *
  • paraLevel can be set to the pseudo-level values + * LEVEL_DEFAULT_LTR and LEVEL_DEFAULT_RTL.
  • + *
+ * + *

+ * The related constants are not real, valid level values. + * DEFAULT_XXX can be used to specify a default for the paragraph + * level for when the setPara() method shall determine it but there + * is no strongly typed character in the input. + *

+ * + * Note that the value for LEVEL_DEFAULT_LTR is even and the one + * for LEVEL_DEFAULT_RTL is odd, just like with normal LTR and RTL + * level values - these special values are designed that way. Also, the + * implementation assumes that MAX_EXPLICIT_LEVEL is odd. + * + *

+ * See Also: + *

    + *
  • {@link #LEVEL_DEFAULT_LTR} + *
  • {@link #LEVEL_DEFAULT_RTL} + *
  • {@link #LEVEL_OVERRIDE} + *
  • {@link #MAX_EXPLICIT_LEVEL} + *
  • {@link #setPara} + *
+ * + *

Basic concept: Reordering Mode

Reordering mode values indicate which + * variant of the Bidi algorithm to use. + * + *

+ * See Also: + *

    + *
  • {@link #setReorderingMode} + *
  • {@link #REORDER_DEFAULT} + *
  • {@link #REORDER_NUMBERS_SPECIAL} + *
  • {@link #REORDER_GROUP_NUMBERS_WITH_R} + *
  • {@link #REORDER_RUNS_ONLY} + *
  • {@link #REORDER_INVERSE_NUMBERS_AS_L} + *
  • {@link #REORDER_INVERSE_LIKE_DIRECT} + *
  • {@link #REORDER_INVERSE_FOR_NUMBERS_SPECIAL} + *
+ * + *

Basic concept: Reordering Options

Reordering options can be applied + * during Bidi text transformations. + * + *

+ * See Also: + *

    + *
  • {@link #setReorderingOptions} + *
  • {@link #OPTION_DEFAULT} + *
  • {@link #OPTION_INSERT_MARKS} + *
  • {@link #OPTION_REMOVE_CONTROLS} + *
  • {@link #OPTION_STREAMING} + *
+ * + * + * @author Simon Montagu, Matitiahu Allouche (ported from C code written by + * Markus W. Scherer) + * @stable ICU 3.8 + * + * + *

Sample code for the ICU Bidi API

+ * + *
Rendering a paragraph with the ICU Bidi API
+ * + * This is (hypothetical) sample code that illustrates how the ICU Bidi + * API could be used to render a paragraph of text. Rendering code + * depends highly on the graphics system, therefore this sample code + * must make a lot of assumptions, which may or may not match any + * existing graphics system's properties. + * + *

+ * The basic assumptions are: + *

+ *
    + *
  • Rendering is done from left to right on a horizontal line.
  • + *
  • A run of single-style, unidirectional text can be rendered at + * once.
  • + *
  • Such a run of text is passed to the graphics system with + * characters (code units) in logical order.
  • + *
  • The line-breaking algorithm is very complicated and + * Locale-dependent - and therefore its implementation omitted from this + * sample code.
  • + *
+ * + *
{@code
+ *
+ *  package com.ibm.icu.dev.test.bidi;
+ *
+ *  import com.ibm.icu.text.Bidi;
+ *  import com.ibm.icu.text.BidiRun;
+ *
+ *  public class Sample {
+ *
+ *      static final int styleNormal = 0;
+ *      static final int styleSelected = 1;
+ *      static final int styleBold = 2;
+ *      static final int styleItalics = 4;
+ *      static final int styleSuper=8;
+ *      static final int styleSub = 16;
+ *
+ *      static class StyleRun {
+ *          int limit;
+ *          int style;
+ *
+ *          public StyleRun(int limit, int style) {
+ *              this.limit = limit;
+ *              this.style = style;
+ *         }
+ *         }
+ *
+ *         static class Bounds {
+ *         int start;
+ *         int limit;
+ *
+ *         public Bounds(int start, int limit) {
+ *         this.start = start;
+ *         this.limit = limit;
+ *         }
+ *         }
+ *
+ *         static int getTextWidth(String text, int start, int limit, StyleRun[] styleRuns, int styleRunCount) {
+ *         // simplistic way to compute the width
+ *         return limit - start;
+ *         }
+ *
+ *         // set limit and StyleRun limit for a line
+ *         	// from text[start] and from styleRuns[styleRunStart]
+ *         	// using Bidi.getLogicalRun(...)
+ *         	// returns line width
+ *         static int getLineBreak(String text, Bounds line, Bidi para, StyleRun styleRuns[], Bounds styleRun) {
+ *         // dummy return
+ *         return 0;
+ *         }
+ *
+ *         // render runs on a line sequentially, always from left to right
+ *
+ *         // prepare rendering a new line
+ *         static void startLine(byte textDirection, int lineWidth) {
+ *         System.out.println();
+ *         }
+ *
+ *         // render a run of text and advance to the right by the run width
+ *         	// the text[start..limit-1] is always in logical order
+ *         static void renderRun(String text, int start, int limit, byte textDirection, int style) {
+ *         }
+ *
+ *         // We could compute a cross-product
+ *         	// from the style runs with the directional runs
+ *         	// and then reorder it.
+ *         	// Instead, here we iterate over each run type
+ *         	// and render the intersections -
+ *         	// with shortcuts in simple (and common) cases.
+ *         	// renderParagraph() is the main function.
+ *
+ *         // render a directional run with
+ *         	// (possibly) multiple style runs intersecting with it
+ *         static void renderDirectionalRun(String text, int start, int limit, byte direction, StyleRun styleRuns[],
+ *         int styleRunCount) {
+ *         int i;
+ *
+ *         // iterate over style runs
+ *         if (direction == Bidi.LTR) {
+ *         int styleLimit;
+ *         for (i = 0; i < styleRunCount; ++i) {
+ *         styleLimit = styleRuns[i].limit;
+ *         if (start < styleLimit) {
+ *         if (styleLimit > limit) {
+ *         styleLimit = limit;
+ *         }
+ *         renderRun(text, start, styleLimit, direction, styleRuns[i].style);
+ *         if (styleLimit == limit) {
+ *         break;
+ *         }
+ *         start = styleLimit;
+ *         }
+ *         }
+ *         } else {
+ *         int styleStart;
+ *
+ *         for (i = styleRunCount - 1; i >= 0; --i) {
+ *         if (i > 0) {
+ *         styleStart = styleRuns[i - 1].limit;
+ *         } else {
+ *         styleStart = 0;
+ *         }
+ *         if (limit >= styleStart) {
+ *         if (styleStart < start) {
+ *         styleStart = start;
+ *         }
+ *         renderRun(text, styleStart, limit, direction, styleRuns[i].style);
+ *         if (styleStart == start) {
+ *         break;
+ *         }
+ *         limit = styleStart;
+ *         }
+ *         }
+ *         }
+ *         }
+ *
+ *         // the line object represents text[start..limit-1]
+ *         static void renderLine(Bidi line, String text, int start, int limit, StyleRun styleRuns[], int styleRunCount) {
+ *         byte direction = line.getDirection();
+ *         if (direction != Bidi.MIXED) {
+ *         // unidirectional
+ *         if (styleRunCount <= 1) {
+ *         renderRun(text, start, limit, direction, styleRuns[0].style);
+ *         } else {
+ *         renderDirectionalRun(text, start, limit, direction, styleRuns, styleRunCount);
+ *         }
+ *         } else {
+ *         // mixed-directional
+ *         int count, i;
+ *         BidiRun run;
+ *
+ *         try {
+ *         count = line.countRuns();
+ *         } catch (IllegalStateException e) {
+ *         e.printStackTrace();
+ *         return;
+ *         }
+ *         if (styleRunCount <= 1) {
+ *         int style = styleRuns[0].style;
+ *
+ *         // iterate over directional runs
+ *         for (i = 0; i < count; ++i) {
+ *         run = line.getVisualRun(i);
+ *         renderRun(text, run.getStart(), run.getLimit(), run.getDirection(), style);
+ *         }
+ *         } else {
+ *         // iterate over both directional and style runs
+ *         for (i = 0; i < count; ++i) {
+ *         run = line.getVisualRun(i);
+ *         renderDirectionalRun(text, run.getStart(), run.getLimit(), run.getDirection(), styleRuns,
+ *         styleRunCount);
+ *         }
+ *         }
+ *         }
+ *         }
+ *
+ *         static void renderParagraph(String text, byte textDirection, StyleRun styleRuns[], int styleRunCount,
+ *         int lineWidth) {
+ *         int length = text.length();
+ *         Bidi para = new Bidi();
+ *         try {
+ *         para.setPara(text, textDirection != 0 ? Bidi.LEVEL_DEFAULT_RTL : Bidi.LEVEL_DEFAULT_LTR, null);
+ *         } catch (Exception e) {
+ *         e.printStackTrace();
+ *         return;
+ *         }
+ *         byte paraLevel = (byte) (1 & para.getParaLevel());
+ *         StyleRun styleRun = new StyleRun(length, styleNormal);
+ *
+ *         if (styleRuns == null || styleRunCount <= 0) {
+ *         styleRuns = new StyleRun[1];
+ *         styleRunCount = 1;
+ *         styleRuns[0] = styleRun;
+ *         }
+ *         // assume styleRuns[styleRunCount-1].limit>=length
+ *
+ *         int width = getTextWidth(text, 0, length, styleRuns, styleRunCount);
+ *         if (width <= lineWidth) {
+ *         // everything fits onto one line
+ *
+ *         // prepare rendering a new line from either left or right
+ *         startLine(paraLevel, width);
+ *
+ *         renderLine(para, text, 0, length, styleRuns, styleRunCount);
+ *         } else {
+ *         // we need to render several lines
+ *         Bidi line = new Bidi(length, 0);
+ *         int start = 0, limit;
+ *         int styleRunStart = 0, styleRunLimit;
+ *
+ *         for (;;) {
+ *         limit = length;
+ *         styleRunLimit = styleRunCount;
+ *         width = getLineBreak(text, new Bounds(start, limit), para, styleRuns,
+ *         new Bounds(styleRunStart, styleRunLimit));
+ *         try {
+ *         line = para.setLine(start, limit);
+ *         } catch (Exception e) {
+ *         e.printStackTrace();
+ *         return;
+ *         }
+ *         // prepare rendering a new line
+ *         				// from either left or right
+ *         startLine(paraLevel, width);
+ *
+ *         if (styleRunStart > 0) {
+ *         int newRunCount = styleRuns.length - styleRunStart;
+ *         StyleRun[] newRuns = new StyleRun[newRunCount];
+ *         System.arraycopy(styleRuns, styleRunStart, newRuns, 0, newRunCount);
+ *         renderLine(line, text, start, limit, newRuns, styleRunLimit - styleRunStart);
+ *         } else {
+ *         renderLine(line, text, start, limit, styleRuns, styleRunLimit - styleRunStart);
+ *         }
+ *         if (limit == length) {
+ *         break;
+ *         }
+ *         start = limit;
+ *         styleRunStart = styleRunLimit - 1;
+ *         if (start >= styleRuns[styleRunStart].limit) {
+ *         ++styleRunStart;
+ *         }
+ *         }
+ *         }
+ *         }
+ *
+ *         public static void main(String[] args) {
+ *         renderParagraph("Some Latin text...", Bidi.LTR, null, 0, 80);
+ *         renderParagraph("Some Hebrew text...", Bidi.RTL, null, 0, 60);
+ *         }
+ *         }
+ *
+ * }
+ */ + +/* + * General implementation notes: + * + * Throughout the implementation, there are comments like (W2) that refer to + * rules of the BiDi algorithm, in this example to the second rule of the + * resolution of weak types. + * + * For handling surrogate pairs, where two UChar's form one "abstract" (or + * UTF-32) character according to UTF-16, the second UChar gets the directional + * property of the entire character assigned, while the first one gets a BN, a + * boundary neutral, type, which is ignored by most of the algorithm according + * to rule (X9) and the implementation suggestions of the BiDi algorithm. + * + * Later, adjustWSLevels() will set the level for each BN to that of the + * following character (UChar), which results in surrogate pairs getting the + * same level on each of their surrogates. + * + * In a UTF-8 implementation, the same thing could be done: the last byte of a + * multi-byte sequence would get the "real" property, while all previous bytes + * of that sequence would get BN. + * + * It is not possible to assign all those parts of a character the same real + * property because this would fail in the resolution of weak types with rules + * that look at immediately surrounding types. + * + * As a related topic, this implementation does not remove Boundary Neutral + * types from the input, but ignores them wherever this is relevant. For + * example, the loop for the resolution of the weak types reads types until it + * finds a non-BN. Also, explicit embedding codes are neither changed into BN + * nor removed. They are only treated the same way real BNs are. As stated + * before, adjustWSLevels() takes care of them at the end. For the purpose of + * conformance, the levels of all these codes do not matter. + * + * Note that this implementation modifies the dirProps after the initial setup, + * when applying X5c (replace FSI by LRI or RLI), X6, N0 (replace paired + * brackets by L or R). + * + * In this implementation, the resolution of weak types (W1 to W6), neutrals (N1 + * and N2), and the assignment of the resolved level (In) are all done in one + * single loop, in resolveImplicitLevels(). Changes of dirProp values are done + * on the fly, without writing them back to the dirProps array. + * + * + * This implementation contains code that allows to bypass steps of the + * algorithm that are not needed on the specific paragraph in order to speed up + * the most common cases considerably, like text that is entirely LTR, or RTL + * text without numbers. + * + * Most of this is done by setting a bit for each directional property in a + * flags variable and later checking for whether there are any LTR characters or + * any RTL characters, or both, whether there are any explicit embedding codes, + * etc. + * + * If the (Xn) steps are performed, then the flags are re-evaluated, because + * they will then not contain the embedding codes any more and will be adjusted + * for override codes, so that subsequently more bypassing may be possible than + * what the initial flags suggested. + * + * If the text is not mixed-directional, then the algorithm steps for the weak + * type resolution are not performed, and all levels are set to the paragraph + * level. + * + * If there are no explicit embedding codes, then the (Xn) steps are not + * performed. + * + * If embedding levels are supplied as a parameter, then all explicit embedding + * codes are ignored, and the (Xn) steps are not performed. + * + * White Space types could get the level of the run they belong to, and are + * checked with a test of (flags&MASK_EMBEDDING) to consider if the paragraph + * direction should be considered in the flags variable. + * + * If there are no White Space types in the paragraph, then (L1) is not + * necessary in adjustWSLevels(). + */ + +// Original filename in ICU4J: Bidi.java +public class BidiBase { + + static class Point { + int pos; /* position in text */ + int flag; /* flag for LRM/RLM, before/after */ + } + + static class InsertPoints { + int size; + int confirmed; + Point[] points = new Point[0]; + } + + static class Opening { + int position; /* position of opening bracket */ + int match; /* matching char or -position of closing bracket */ + int contextPos; /* position of last strong char found before opening */ + short flags; /* bits for L or R/AL found within the pair */ + byte contextDir; /* L or R according to last strong char before opening */ + } + + static class IsoRun { + int contextPos; /* position of char determining context */ + short start; /* index of first opening entry for this run */ + short limit; /* index after last opening entry for this run */ + byte level; /* level of this run */ + byte lastStrong; /* bidi class of last strong char found in this run */ + byte lastBase; /* bidi class of last base char found in this run */ + byte contextDir; /* L or R to use as context for following openings */ + } + + static class BracketData { + Opening[] openings = new Opening[SIMPLE_PARAS_COUNT]; + int isoRunLast; /* index of last used entry */ + /* + * array of nested isolated sequence entries; can never excess + * UBIDI_MAX_EXPLICIT_LEVEL + 1 for index 0, + 1 for before the first isolated + * sequence + */ + IsoRun[] isoRuns = new IsoRun[MAX_EXPLICIT_LEVEL + 2]; + boolean isNumbersSpecial; /* reordering mode for NUMBERS_SPECIAL */ + } + + static class Isolate { + int startON; + int start1; + short stateImp; + short state; + } + + /** + * Paragraph level setting + *

+ * + * Constant indicating that the base direction depends on the first strong + * directional character in the text according to the Unicode Bidirectional + * Algorithm. If no strong directional character is present, then set the + * paragraph level to 0 (left-to-right). + *

+ * + * If this value is used in conjunction with reordering modes + * REORDER_INVERSE_LIKE_DIRECT or + * REORDER_INVERSE_FOR_NUMBERS_SPECIAL, the text to reorder is + * assumed to be visual LTR, and the text after reordering is required to be the + * corresponding logical string with appropriate contextual direction. The + * direction of the result string will be RTL if either the rightmost or + * leftmost strong character of the source text is RTL or Arabic Letter, the + * direction will be LTR otherwise. + *

+ * + * If reordering option OPTION_INSERT_MARKS is set, an RLM may be + * added at the beginning of the result string to ensure round trip (that the + * result string, when reordered back to visual, will produce the original + * source text). + * + * @see #REORDER_INVERSE_LIKE_DIRECT + * @see #REORDER_INVERSE_FOR_NUMBERS_SPECIAL + * @stable ICU 3.8 + */ + public static final byte LEVEL_DEFAULT_LTR = (byte) 0x7e; + + /** + * Paragraph level setting + *

+ * + * Constant indicating that the base direction depends on the first strong + * directional character in the text according to the Unicode Bidirectional + * Algorithm. If no strong directional character is present, then set the + * paragraph level to 1 (right-to-left). + *

+ * + * If this value is used in conjunction with reordering modes + * REORDER_INVERSE_LIKE_DIRECT or + * REORDER_INVERSE_FOR_NUMBERS_SPECIAL, the text to reorder is + * assumed to be visual LTR, and the text after reordering is required to be the + * corresponding logical string with appropriate contextual direction. The + * direction of the result string will be RTL if either the rightmost or + * leftmost strong character of the source text is RTL or Arabic Letter, or if + * the text contains no strong character; the direction will be LTR otherwise. + *

+ * + * If reordering option OPTION_INSERT_MARKS is set, an RLM may be + * added at the beginning of the result string to ensure round trip (that the + * result string, when reordered back to visual, will produce the original + * source text). + * + * @see #REORDER_INVERSE_LIKE_DIRECT + * @see #REORDER_INVERSE_FOR_NUMBERS_SPECIAL + * @stable ICU 3.8 + */ + public static final byte LEVEL_DEFAULT_RTL = (byte) 0x7f; + + /** + * Maximum explicit embedding level. (The maximum resolved level can be up to + * MAX_EXPLICIT_LEVEL+1). + * + * @stable ICU 3.8 + */ + public static final byte MAX_EXPLICIT_LEVEL = 125; + + /** + * Bit flag for level input. Overrides directional properties. + * + * @stable ICU 3.8 + */ + public static final byte LEVEL_OVERRIDE = (byte) 0x80; + + /** + * Special value which can be returned by the mapping methods when a logical + * index has no corresponding visual index or vice-versa. This may happen for + * the logical-to-visual mapping of a Bidi control when option + * OPTION_REMOVE_CONTROLS is specified. This can also happen for + * the visual-to-logical mapping of a Bidi mark (LRM or RLM) inserted by option + * OPTION_INSERT_MARKS. + * + * @see #getVisualIndex + * @see #getVisualMap + * @see #getLogicalIndex + * @see #getLogicalMap + * @see #OPTION_INSERT_MARKS + * @see #OPTION_REMOVE_CONTROLS + * @stable ICU 3.8 + */ + public static final int MAP_NOWHERE = -1; + + /** + * Left-to-right text. + *

    + *
  • As return value for getDirection(), it means that the source + * string contains no right-to-left characters, or that the source string is + * empty and the paragraph level is even. + *
  • As return value for getBaseDirection(), it means that the + * first strong character of the source string has a left-to-right direction. + *
+ * + * @stable ICU 3.8 + */ + public static final byte LTR = 0; + + /** + * Right-to-left text. + *
    + *
  • As return value for getDirection(), it means that the source + * string contains no left-to-right characters, or that the source string is + * empty and the paragraph level is odd. + *
  • As return value for getBaseDirection(), it means that the + * first strong character of the source string has a right-to-left direction. + *
+ * + * @stable ICU 3.8 + */ + public static final byte RTL = 1; + + /** + * Mixed-directional text. + *

+ * As return value for getDirection(), it means that the source + * string contains both left-to-right and right-to-left characters. + * + * @stable ICU 3.8 + */ + public static final byte MIXED = 2; + + /** + * option bit for writeReordered(): keep combining characters after their base + * characters in RTL runs + * + * @see #writeReordered + * @stable ICU 3.8 + */ + public static final short KEEP_BASE_COMBINING = 1; + + /** + * option bit for writeReordered(): replace characters with the "mirrored" + * property in RTL runs by their mirror-image mappings + * + * @see #writeReordered + * @stable ICU 3.8 + */ + public static final short DO_MIRRORING = 2; + + /** + * option bit for writeReordered(): surround the run with LRMs if necessary; + * this is part of the approximate "inverse Bidi" algorithm + * + *

+ * This option does not imply corresponding adjustment of the index mappings. + *

+ * + * @see #setInverse + * @see #writeReordered + * @stable ICU 3.8 + */ + public static final short INSERT_LRM_FOR_NUMERIC = 4; + + /** + * option bit for writeReordered(): remove Bidi control characters (this does + * not affect INSERT_LRM_FOR_NUMERIC) + * + *

+ * This option does not imply corresponding adjustment of the index mappings. + *

+ * + * @see #writeReordered + * @see #INSERT_LRM_FOR_NUMERIC + * @stable ICU 3.8 + */ + public static final short REMOVE_BIDI_CONTROLS = 8; + + /** + * option bit for writeReordered(): write the output in reverse order + * + *

+ * This has the same effect as calling writeReordered() first + * without this option, and then calling writeReverse() without + * mirroring. Doing this in the same step is faster and avoids a temporary + * buffer. An example for using this option is output to a character terminal + * that is designed for RTL scripts and stores text in reverse order. + *

+ * + * @see #writeReordered + * @stable ICU 3.8 + */ + public static final short OUTPUT_REVERSE = 16; + + /** + * Reordering mode: Regular Logical to Visual Bidi algorithm according to + * Unicode. + * + * @see #setReorderingMode + * @stable ICU 3.8 + */ + private static final short REORDER_DEFAULT = 0; + + /** + * Reordering mode: Logical to Visual algorithm which handles numbers in a way + * which mimicks the behavior of Windows XP. + * + * @see #setReorderingMode + * @stable ICU 3.8 + */ + private static final short REORDER_NUMBERS_SPECIAL = 1; + + /** + * Reordering mode: Logical to Visual algorithm grouping numbers with adjacent R + * characters (reversible algorithm). + * + * @see #setReorderingMode + * @stable ICU 3.8 + */ + private static final short REORDER_GROUP_NUMBERS_WITH_R = 2; + + /** + * Reordering mode: Reorder runs only to transform a Logical LTR string to the + * logical RTL string with the same display, or vice-versa.
+ * If this mode is set together with option OPTION_INSERT_MARKS, + * some Bidi controls in the source text may be removed and other controls may + * be added to produce the minimum combination which has the required display. + * + * @see #OPTION_INSERT_MARKS + * @see #setReorderingMode + * @stable ICU 3.8 + */ + static final short REORDER_RUNS_ONLY = 3; + + /** + * Reordering mode: Visual to Logical algorithm which handles numbers like L + * (same algorithm as selected by setInverse(true). + * + * @see #setInverse + * @see #setReorderingMode + * @stable ICU 3.8 + */ + static final short REORDER_INVERSE_NUMBERS_AS_L = 4; + + /** + * Reordering mode: Visual to Logical algorithm equivalent to the regular + * Logical to Visual algorithm. + * + * @see #setReorderingMode + * @stable ICU 3.8 + */ + static final short REORDER_INVERSE_LIKE_DIRECT = 5; + + /** + * Reordering mode: Inverse Bidi (Visual to Logical) algorithm for the + * REORDER_NUMBERS_SPECIAL Bidi algorithm. + * + * @see #setReorderingMode + * @stable ICU 3.8 + */ + static final short REORDER_INVERSE_FOR_NUMBERS_SPECIAL = 6; + + /* + * Reordering mode values must be ordered so that all the regular logical to + * visual modes come first, and all inverse Bidi modes come last. + */ + private static final short REORDER_LAST_LOGICAL_TO_VISUAL = REORDER_NUMBERS_SPECIAL; + + /** + * Option bit for setReorderingOptions: insert Bidi marks (LRM or + * RLM) when needed to ensure correct result of a reordering to a Logical order + * + *

+ * This option must be set or reset before calling setPara. + *

+ * + *

+ * This option is significant only with reordering modes which generate a result + * with Logical order, specifically. + *

+ *
    + *
  • REORDER_RUNS_ONLY
  • + *
  • REORDER_INVERSE_NUMBERS_AS_L
  • + *
  • REORDER_INVERSE_LIKE_DIRECT
  • + *
  • REORDER_INVERSE_FOR_NUMBERS_SPECIAL
  • + *
+ * + *

+ * If this option is set in conjunction with reordering mode + * REORDER_INVERSE_NUMBERS_AS_L or with calling + * setInverse(true), it implies option + * INSERT_LRM_FOR_NUMERIC in calls to method + * writeReordered(). + *

+ * + *

+ * For other reordering modes, a minimum number of LRM or RLM characters will be + * added to the source text after reordering it so as to ensure round trip, i.e. + * when applying the inverse reordering mode on the resulting logical text with + * removal of Bidi marks (option OPTION_REMOVE_CONTROLS set before + * calling setPara() or option REMOVE_BIDI_CONTROLS in + * writeReordered), the result will be identical to the source text + * in the first transformation. + * + *

+ * This option will be ignored if specified together with option + * OPTION_REMOVE_CONTROLS. It inhibits option + * REMOVE_BIDI_CONTROLS in calls to method + * writeReordered() and it implies option + * INSERT_LRM_FOR_NUMERIC in calls to method + * writeReordered() if the reordering mode is + * REORDER_INVERSE_NUMBERS_AS_L. + *

+ * + * @see #setReorderingMode + * @see #setReorderingOptions + * @see #INSERT_LRM_FOR_NUMERIC + * @see #REMOVE_BIDI_CONTROLS + * @see #OPTION_REMOVE_CONTROLS + * @see #REORDER_RUNS_ONLY + * @see #REORDER_INVERSE_NUMBERS_AS_L + * @see #REORDER_INVERSE_LIKE_DIRECT + * @see #REORDER_INVERSE_FOR_NUMBERS_SPECIAL + * @stable ICU 3.8 + */ + static final int OPTION_INSERT_MARKS = 1; + + /** + * Option bit for setReorderingOptions: remove Bidi control + * characters + * + *

+ * This option must be set or reset before calling setPara. + *

+ * + *

+ * This option nullifies option OPTION_INSERT_MARKS. It inhibits + * option INSERT_LRM_FOR_NUMERIC in calls to method + * writeReordered() and it implies option + * REMOVE_BIDI_CONTROLS in calls to that method. + *

+ * + * @see #setReorderingMode + * @see #setReorderingOptions + * @see #OPTION_INSERT_MARKS + * @see #INSERT_LRM_FOR_NUMERIC + * @see #REMOVE_BIDI_CONTROLS + * @stable ICU 3.8 + */ + static final int OPTION_REMOVE_CONTROLS = 2; + + /** + * Option bit for setReorderingOptions: process the output as part + * of a stream to be continued + * + *

+ * This option must be set or reset before calling setPara. + *

+ * + *

+ * This option specifies that the caller is interested in processing large text + * object in parts. The results of the successive calls are expected to be + * concatenated by the caller. Only the call for the last part will have this + * option bit off. + *

+ * + *

+ * When this option bit is on, setPara() may process less than the + * full source text in order to truncate the text at a meaningful boundary. The + * caller should call getProcessedLength() immediately after + * calling setPara() in order to determine how much of the source + * text has been processed. Source text beyond that length should be resubmitted + * in following calls to setPara. The processed length may be less + * than the length of the source text if a character preceding the last + * character of the source text constitutes a reasonable boundary (like a block + * separator) for text to be continued.
+ * If the last character of the source text constitutes a reasonable boundary, + * the whole text will be processed at once.
+ * If nowhere in the source text there exists such a reasonable boundary, the + * processed length will be zero.
+ * The caller should check for such an occurrence and do one of the following: + *

    + *
  • submit a larger amount of text with a better chance to include a + * reasonable boundary.
  • + *
  • resubmit the same text after turning off option + * OPTION_STREAMING.
  • + *
+ * In all cases, this option should be turned off before processing the last + * part of the text. + *

+ * + *

+ * When the OPTION_STREAMING option is used, it is recommended to + * call orderParagraphsLTR(true) before calling + * setPara() so that later paragraphs may be concatenated to + * previous paragraphs on the right. + *

+ * + * @see #setReorderingMode + * @see #setReorderingOptions + * @see #getProcessedLength + * @stable ICU 3.8 + */ + private static final int OPTION_STREAMING = 4; + + /* + * Comparing the description of the Bidi algorithm with this implementation is + * easier with the same names for the Bidi types in the code as there. See + * UCharacterDirection + */ + /* private */ static final byte L = 0; + private static final byte R = 1; + private static final byte EN = 2; + private static final byte ES = 3; + private static final byte ET = 4; + private static final byte AN = 5; + private static final byte CS = 6; + static final byte B = 7; + private static final byte S = 8; + private static final byte WS = 9; + private static final byte ON = 10; + private static final byte LRE = 11; + private static final byte LRO = 12; + private static final byte AL = 13; + private static final byte RLE = 14; + private static final byte RLO = 15; + private static final byte PDF = 16; + private static final byte NSM = 17; + private static final byte BN = 18; + private static final byte FSI = 19; + private static final byte LRI = 20; + private static final byte RLI = 21; + private static final byte PDI = 22; + private static final byte ENL = PDI + 1; /* EN after W7 */ + private static final byte ENR = ENL + 1; /* EN not subject to W7 */ + + // Number of directional types + private static final int CHAR_DIRECTION_COUNT = 23; + + /** + * Enumerated property Bidi_Paired_Bracket_Type (new in Unicode 6.3). Used in + * Unicode Standard Annex #9: + * Unicode Bidirectional Algorithm. Returns UCharacter.BidiPairedBracketType + * values. + * + * @stable ICU 52 + */ + public static final int BIDI_PAIRED_BRACKET_TYPE = 0x1015; + + /** + * Bidi Paired Bracket Type constants. + * + * @see UProperty#BIDI_PAIRED_BRACKET_TYPE + * @stable ICU 52 + */ + public static interface BidiPairedBracketType { + /** + * Not a paired bracket. + * + * @stable ICU 52 + */ + public static final int NONE = 0; + /** + * Open paired bracket. + * + * @stable ICU 52 + */ + public static final int OPEN = 1; + /** + * Close paired bracket. + * + * @stable ICU 52 + */ + public static final int CLOSE = 2; + /** + * @stable ICU 52 + */ + public static final int COUNT = 3; + } + + /* number of paras entries allocated initially */ + static final int SIMPLE_PARAS_COUNT = 10; + + private static final char CR = '\r'; + private static final char LF = '\n'; + + static final int LRM_BEFORE = 1; + static final int LRM_AFTER = 2; + static final int RLM_BEFORE = 4; + static final int RLM_AFTER = 8; + + /* flags for Opening.flags */ + static final byte FOUND_L = (byte) DirPropFlag(L); + static final byte FOUND_R = (byte) DirPropFlag(R); + + /* + * The following bit is used for the directional isolate status. Stack entries + * corresponding to isolate sequences are greater than ISOLATE. + */ + static final int ISOLATE = 0x0100; + + /* + * reference to parent paragraph object (reference to self if this object is a + * paragraph object); set to null in a newly opened object; set to a real value + * after a successful execution of setPara or setLine + */ + BidiBase paraBidi; + + final UBiDiProps bdp; + + /* character array representing the current text */ + char[] text; + + /* length of the current text */ + int originalLength; + + /* + * if the option OPTION_STREAMING is set, this is the length of text actually + * processed by setPara, which may be shorter than the original + * length. Otherwise, it is identical to the original length. + */ + public int length; + + /* + * if option OPTION_REMOVE_CONTROLS is set, and/or Bidi marks are allowed to be + * inserted in one of the reordering modes, the length of the result string may + * be different from the processed length. + */ + int resultLength; + + /* indicators for whether memory may be allocated after construction */ + boolean mayAllocateText; + boolean mayAllocateRuns; + + /* arrays with one value per text-character */ + byte[] dirPropsMemory = new byte[1]; + byte[] levelsMemory = new byte[1]; + byte[] dirProps; + byte[] levels; + + /* are we performing an approximation of the "inverse Bidi" algorithm? */ + boolean isInverse; + + /* are we using the basic algorithm or its variation? */ + int reorderingMode; + + /* bitmask for reordering options */ + int reorderingOptions; + + /* must block separators receive level 0? */ + boolean orderParagraphsLTR; + + /* the paragraph level */ + byte paraLevel; + + /* original paraLevel when contextual */ + /* must be one of DEFAULT_xxx or 0 if not contextual */ + byte defaultParaLevel; + + /* the following is set in setPara, used in processPropertySeq */ + + ImpTabPair impTabPair; /* reference to levels state table pair */ + + /* the overall paragraph or line directionality */ + byte direction; + + /* flags is a bit set for which directional properties are in the text */ + int flags; + + /* lastArabicPos is index to the last AL in the text, -1 if none */ + int lastArabicPos; + + /* characters after trailingWSStart are WS and are */ + /* implicitly at the paraLevel (rule (L1)) - levels may not reflect that */ + int trailingWSStart; + + /* fields for paragraph handling, set in getDirProps() */ + int paraCount; + int[] paras_limit = new int[SIMPLE_PARAS_COUNT]; + byte[] paras_level = new byte[SIMPLE_PARAS_COUNT]; + + /* fields for line reordering */ + int runCount; /* ==-1: runs not set up yet */ + BidiRun[] runsMemory = new BidiRun[0]; + BidiRun[] runs; + + /* for non-mixed text, we only need a tiny array of runs (no allocation) */ + BidiRun[] simpleRuns = { new BidiRun() }; + + /* fields for managing isolate sequences */ + Isolate[] isolates; + + /* maximum or current nesting depth of isolate sequences */ + /* + * Within resolveExplicitLevels() and checkExplicitLevels(), this is the maximal + * nesting encountered. Within resolveImplicitLevels(), this is the index of the + * current isolates stack entry. + */ + int isolateCount; + + /* mapping of runs in logical order to visual order */ + int[] logicalToVisualRunsMap; + /* flag to indicate that the map has been updated */ + boolean isGoodLogicalToVisualRunsMap; + + /* for inverse Bidi with insertion of directional marks */ + InsertPoints insertPoints = new InsertPoints(); + + /* for option OPTION_REMOVE_CONTROLS */ + int controlCount; + + /* + * Sometimes, bit values are more appropriate to deal with directionality + * properties. Abbreviations in these method names refer to names used in the + * Bidi algorithm. + */ + static int DirPropFlag(byte dir) { + return (1 << dir); + } + + boolean testDirPropFlagAt(int flag, int index) { + return ((DirPropFlag(dirProps[index]) & flag) != 0); + } + + static final int DirPropFlagMultiRuns = DirPropFlag((byte) 31); + + /* to avoid some conditional statements, use tiny constant arrays */ + static final int DirPropFlagLR[] = { DirPropFlag(L), DirPropFlag(R) }; + static final int DirPropFlagE[] = { DirPropFlag(LRE), DirPropFlag(RLE) }; + static final int DirPropFlagO[] = { DirPropFlag(LRO), DirPropFlag(RLO) }; + + static final int DirPropFlagLR(byte level) { + return DirPropFlagLR[level & 1]; + } + + static final int DirPropFlagE(byte level) { + return DirPropFlagE[level & 1]; + } + + static final int DirPropFlagO(byte level) { + return DirPropFlagO[level & 1]; + } + + static final byte DirFromStrong(byte strong) { + return strong == L ? L : R; + } + + static final byte NoOverride(byte level) { + return (byte) (level & ~LEVEL_OVERRIDE); + } + + /* are there any characters that are LTR or RTL? */ + static final int MASK_LTR = DirPropFlag(L) | DirPropFlag(EN) | DirPropFlag(ENL) | DirPropFlag(ENR) | DirPropFlag(AN) + | DirPropFlag(LRE) | DirPropFlag(LRO) | DirPropFlag(LRI); + static final int MASK_RTL = DirPropFlag(R) | DirPropFlag(AL) | DirPropFlag(RLE) | DirPropFlag(RLO) + | DirPropFlag(RLI); + + static final int MASK_R_AL = DirPropFlag(R) | DirPropFlag(AL); + + /* explicit embedding codes */ + private static final int MASK_EXPLICIT = DirPropFlag(LRE) | DirPropFlag(LRO) | DirPropFlag(RLE) | DirPropFlag(RLO) + | DirPropFlag(PDF); + private static final int MASK_BN_EXPLICIT = DirPropFlag(BN) | MASK_EXPLICIT; + + /* explicit isolate codes */ + private static final int MASK_ISO = DirPropFlag(LRI) | DirPropFlag(RLI) | DirPropFlag(FSI) | DirPropFlag(PDI); + + /* paragraph and segment separators */ + private static final int MASK_B_S = DirPropFlag(B) | DirPropFlag(S); + + /* all types that are counted as White Space or Neutral in some steps */ + static final int MASK_WS = MASK_B_S | DirPropFlag(WS) | MASK_BN_EXPLICIT | MASK_ISO; + + /* types that are neutrals or could becomes neutrals in (Wn) */ + private static final int MASK_POSSIBLE_N = DirPropFlag(ON) | DirPropFlag(CS) | DirPropFlag(ES) | DirPropFlag(ET) + | MASK_WS; + + /* + * These types may be changed to "e", the embedding type (L or R) of the run, in + * the Bidi algorithm (N2) + */ + private static final int MASK_EMBEDDING = DirPropFlag(NSM) | MASK_POSSIBLE_N; + + /* + * the dirProp's L and R are defined to 0 and 1 values in + * UCharacterDirection.java + */ + private static byte GetLRFromLevel(byte level) { + return (byte) (level & 1); + } + + private static boolean IsDefaultLevel(byte level) { + return ((level & LEVEL_DEFAULT_LTR) == LEVEL_DEFAULT_LTR); + } + + static boolean IsBidiControlChar(int c) { + /* + * check for range 0x200c to 0x200f (ZWNJ, ZWJ, LRM, RLM) or 0x202a to 0x202e + * (LRE, RLE, PDF, LRO, RLO) + */ + return (((c & 0xfffffffc) == 0x200c) || ((c >= 0x202a) && (c <= 0x202e)) || ((c >= 0x2066) && (c <= 0x2069))); + } + + void verifyValidPara() { + if (!(this == this.paraBidi)) { + throw new IllegalStateException(); + } + } + + void verifyValidParaOrLine() { + BidiBase para = this.paraBidi; + /* verify Para */ + if (this == para) { + return; + } + /* verify Line */ + if ((para == null) || (para != para.paraBidi)) { + throw new IllegalStateException(); + } + } + + void verifyRange(int index, int start, int limit) { + if (index < start || index >= limit) { + throw new IllegalArgumentException("Value " + index + " is out of range " + start + " to " + limit); + } + } + + /** + * Allocate a Bidi object with preallocated memory for internal + * structures. This method provides a Bidi object like the default + * constructor but it also preallocates memory for internal structures according + * to the sizings supplied by the caller. + *

+ * The preallocation can be limited to some of the internal memory by setting + * some values to 0 here. That means that if, e.g., maxRunCount + * cannot be reasonably predetermined and should not be set to + * maxLength (the only failproof value) to avoid wasting memory, + * then maxRunCount could be set to 0 here and the internal + * structures that are associated with it will be allocated on demand, just like + * with the default constructor. + * + * @param maxLength is the maximum text or line length that internal memory + * will be preallocated for. An attempt to associate this + * object with a longer text will fail, unless this value is + * 0, which leaves the allocation up to the implementation. + * + * @param maxRunCount is the maximum anticipated number of same-level runs that + * internal memory will be preallocated for. An attempt to + * access visual runs on an object that was not preallocated + * for as many runs as the text was actually resolved to will + * fail, unless this value is 0, which leaves the allocation + * up to the implementation.
+ *
+ * The number of runs depends on the actual text and maybe + * anywhere between 1 and maxLength. It is + * typically small. + * + * @throws IllegalArgumentException if maxLength or maxRunCount is less than 0 + * @stable ICU 3.8 + */ + public BidiBase(int maxLength, int maxRunCount) { + /* check the argument values */ + if (maxLength < 0 || maxRunCount < 0) { + throw new IllegalArgumentException(); + } + + /* + * reset the object, all reference variables null, all flags false, all sizes 0. + * In fact, we don't need to do anything, since class members are initialized as + * zero when an instance is created. + */ + /* + * mayAllocateText = false; mayAllocateRuns = false; orderParagraphsLTR = false; + * paraCount = 0; runCount = 0; trailingWSStart = 0; flags = 0; paraLevel = 0; + * defaultParaLevel = 0; direction = 0; + */ + /* get Bidi properties */ + bdp = UBiDiProps.INSTANCE; + + /* allocate memory for arrays as requested */ + if (maxLength > 0) { + getInitialDirPropsMemory(maxLength); + getInitialLevelsMemory(maxLength); + } else { + mayAllocateText = true; + } + + if (maxRunCount > 0) { + // if maxRunCount == 1, use simpleRuns[] + if (maxRunCount > 1) { + getInitialRunsMemory(maxRunCount); + } + } else { + mayAllocateRuns = true; + } + } + + /* + * We are allowed to allocate memory if object==null or mayAllocate==true for + * each array that we need. + * + * Assume sizeNeeded>0. If object != null, then assume size > 0. + */ + private Object getMemory(String label, Object array, Class arrayClass, boolean mayAllocate, int sizeNeeded) { + int len = Array.getLength(array); + + /* we have at least enough memory and must not allocate */ + if (sizeNeeded == len) { + return array; + } + if (!mayAllocate) { + /* we must not allocate */ + if (sizeNeeded <= len) { + return array; + } + throw new OutOfMemoryError("Failed to allocate memory for " + label); + } + /* we may try to grow or shrink */ + /* + * FOOD FOR THOUGHT: when shrinking it should be possible to avoid the + * allocation altogether and rely on this.length + */ + try { + return Array.newInstance(arrayClass, sizeNeeded); + } catch (Exception e) { + throw new OutOfMemoryError("Failed to allocate memory for " + label); + } + } + + /* helper methods for each allocated array */ + private void getDirPropsMemory(boolean mayAllocate, int len) { + Object array = getMemory("DirProps", dirPropsMemory, Byte.TYPE, mayAllocate, len); + dirPropsMemory = (byte[]) array; + } + + void getDirPropsMemory(int len) { + getDirPropsMemory(mayAllocateText, len); + } + + private void getLevelsMemory(boolean mayAllocate, int len) { + Object array = getMemory("Levels", levelsMemory, Byte.TYPE, mayAllocate, len); + levelsMemory = (byte[]) array; + } + + void getLevelsMemory(int len) { + getLevelsMemory(mayAllocateText, len); + } + + private void getRunsMemory(boolean mayAllocate, int len) { + Object array = getMemory("Runs", runsMemory, BidiRun.class, mayAllocate, len); + runsMemory = (BidiRun[]) array; + } + + void getRunsMemory(int len) { + getRunsMemory(mayAllocateRuns, len); + } + + /* additional methods used by constructor - always allow allocation */ + private void getInitialDirPropsMemory(int len) { + getDirPropsMemory(true, len); + } + + private void getInitialLevelsMemory(int len) { + getLevelsMemory(true, len); + } + + private void getInitialRunsMemory(int len) { + getRunsMemory(true, len); + } + + /** + * Is this Bidi object set to perform the inverse Bidi algorithm? + *

+ * Note: calling this method after setting the reordering mode with + * setReorderingMode will return true if the + * reordering mode was set to REORDER_INVERSE_NUMBERS_AS_L, + * false for all other values. + *

+ * + * @return true if the Bidi object is set to perform + * the inverse Bidi algorithm by handling numbers as L. + * + * @see #setInverse + * @see #setReorderingMode + * @see #REORDER_INVERSE_NUMBERS_AS_L + * @stable ICU 3.8 + */ + public boolean isInverse() { + return isInverse; + } + + /* perform (P2)..(P3) ------------------------------------------------------- */ + + /* + * Check that there are enough entries in the arrays paras_limit and paras_level + */ + private void checkParaCount() { + int[] saveLimits; + byte[] saveLevels; + int count = paraCount; + if (count <= paras_level.length) + return; + int oldLength = paras_level.length; + saveLimits = paras_limit; + saveLevels = paras_level; + try { + paras_limit = new int[count * 2]; + paras_level = new byte[count * 2]; + } catch (Exception e) { + throw new OutOfMemoryError("Failed to allocate memory for paras"); + } + System.arraycopy(saveLimits, 0, paras_limit, 0, oldLength); + System.arraycopy(saveLevels, 0, paras_level, 0, oldLength); + } + + /* + * Get the directional properties for the text, calculate the flags bit-set, and + * determine the paragraph level if necessary (in paras_level[i]). FSI + * initiators are also resolved and their dirProp replaced with LRI or RLI. When + * encountering an FSI, it is initially replaced with an LRI, which is the + * default. Only if a strong R or AL is found within its scope will the LRI be + * replaced by an RLI. + */ + static final int NOT_SEEKING_STRONG = 0; /* 0: not contextual paraLevel, not after FSI */ + static final int SEEKING_STRONG_FOR_PARA = 1; /* 1: looking for first strong char in para */ + static final int SEEKING_STRONG_FOR_FSI = 2; /* 2: looking for first strong after FSI */ + static final int LOOKING_FOR_PDI = 3; /* 3: found strong after FSI, looking for PDI */ + + private void getDirProps() { + int i = 0, i0, i1; + flags = 0; /* collect all directionalities in the text */ + int uchar; + byte dirProp; + byte defaultParaLevel = 0; /* initialize to avoid compiler warnings */ + boolean isDefaultLevel = IsDefaultLevel(paraLevel); + /* + * for inverse Bidi, the default para level is set to RTL if there is a strong R + * or AL character at either end of the text + */ + boolean isDefaultLevelInverse = isDefaultLevel && (reorderingMode == REORDER_INVERSE_LIKE_DIRECT + || reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL); + lastArabicPos = -1; + int controlCount = 0; + boolean removeBidiControls = (reorderingOptions & OPTION_REMOVE_CONTROLS) != 0; + + byte state; + byte lastStrong = ON; /* for default level & inverse Bidi */ + /* + * The following stacks are used to manage isolate sequences. Those sequences + * may be nested, but obviously never more deeply than the maximum explicit + * embedding level. lastStack is the index of the last used entry in the stack. + * A value of -1 means that there is no open isolate sequence. lastStack is + * reset to -1 on paragraph boundaries. + */ + /* + * The following stack contains the position of the initiator of each open + * isolate sequence + */ + int[] isolateStartStack = new int[MAX_EXPLICIT_LEVEL + 1]; + /* + * The following stack contains the last known state before encountering the + * initiator of an isolate sequence + */ + byte[] previousStateStack = new byte[MAX_EXPLICIT_LEVEL + 1]; + int stackLast = -1; + + if ((reorderingOptions & OPTION_STREAMING) != 0) + length = 0; + defaultParaLevel = (byte) (paraLevel & 1); + + if (isDefaultLevel) { + paras_level[0] = defaultParaLevel; + lastStrong = defaultParaLevel; + state = SEEKING_STRONG_FOR_PARA; + } else { + paras_level[0] = paraLevel; + state = NOT_SEEKING_STRONG; + } + /* count paragraphs and determine the paragraph level (P2..P3) */ + /* + * see comment on constant fields: the LEVEL_DEFAULT_XXX values are designed so + * that their low-order bit alone yields the intended default + */ + + for (i = 0; i < originalLength; /* i is incremented in the loop */) { + i0 = i; /* index of first code unit */ + uchar = UTF16.charAt(text, 0, originalLength, i); + i += UTF16.getCharCount(uchar); + i1 = i - 1; /* index of last code unit, gets the directional property */ + + dirProp = (byte) getCustomizedClass(uchar); + flags |= DirPropFlag(dirProp); + dirProps[i1] = dirProp; + if (i1 > i0) { /* set previous code units' properties to BN */ + flags |= DirPropFlag(BN); + do { + dirProps[--i1] = BN; + } while (i1 > i0); + } + if (removeBidiControls && IsBidiControlChar(uchar)) { + controlCount++; + } + if (dirProp == L) { + if (state == SEEKING_STRONG_FOR_PARA) { + paras_level[paraCount - 1] = 0; + state = NOT_SEEKING_STRONG; + } else if (state == SEEKING_STRONG_FOR_FSI) { + if (stackLast <= MAX_EXPLICIT_LEVEL) { + /* no need for next statement, already set by default */ + /* dirProps[isolateStartStack[stackLast]] = LRI; */ + flags |= DirPropFlag(LRI); + } + state = LOOKING_FOR_PDI; + } + lastStrong = L; + continue; + } + if (dirProp == R || dirProp == AL) { + if (state == SEEKING_STRONG_FOR_PARA) { + paras_level[paraCount - 1] = 1; + state = NOT_SEEKING_STRONG; + } else if (state == SEEKING_STRONG_FOR_FSI) { + if (stackLast <= MAX_EXPLICIT_LEVEL) { + dirProps[isolateStartStack[stackLast]] = RLI; + flags |= DirPropFlag(RLI); + } + state = LOOKING_FOR_PDI; + } + lastStrong = R; + if (dirProp == AL) + lastArabicPos = i - 1; + continue; + } + if (dirProp >= FSI && dirProp <= RLI) { /* FSI, LRI or RLI */ + stackLast++; + if (stackLast <= MAX_EXPLICIT_LEVEL) { + isolateStartStack[stackLast] = i - 1; + previousStateStack[stackLast] = state; + } + if (dirProp == FSI) { + dirProps[i - 1] = LRI; /* default if no strong char */ + state = SEEKING_STRONG_FOR_FSI; + } else + state = LOOKING_FOR_PDI; + continue; + } + if (dirProp == PDI) { + if (state == SEEKING_STRONG_FOR_FSI) { + if (stackLast <= MAX_EXPLICIT_LEVEL) { + /* no need for next statement, already set by default */ + /* dirProps[isolateStartStack[stackLast]] = LRI; */ + flags |= DirPropFlag(LRI); + } + } + if (stackLast >= 0) { + if (stackLast <= MAX_EXPLICIT_LEVEL) + state = previousStateStack[stackLast]; + stackLast--; + } + continue; + } + if (dirProp == B) { + if (i < originalLength && uchar == CR && text[i] == LF) /* do nothing on the CR */ + continue; + paras_limit[paraCount - 1] = i; + if (isDefaultLevelInverse && lastStrong == R) + paras_level[paraCount - 1] = 1; + if ((reorderingOptions & OPTION_STREAMING) != 0) { + /* + * When streaming, we only process whole paragraphs thus some updates are only + * done on paragraph boundaries + */ + length = i; /* i is index to next character */ + this.controlCount = controlCount; + } + if (i < originalLength) { /* B not last char in text */ + paraCount++; + checkParaCount(); /* check that there is enough memory for a new para entry */ + if (isDefaultLevel) { + paras_level[paraCount - 1] = defaultParaLevel; + state = SEEKING_STRONG_FOR_PARA; + lastStrong = defaultParaLevel; + } else { + paras_level[paraCount - 1] = paraLevel; + state = NOT_SEEKING_STRONG; + } + stackLast = -1; + } + continue; + } + } + /* +Ignore still open isolate sequences with overflow */ + if (stackLast > MAX_EXPLICIT_LEVEL) { + stackLast = MAX_EXPLICIT_LEVEL; + state = SEEKING_STRONG_FOR_FSI; /* to be on the safe side */ + } + /* Resolve direction of still unresolved open FSI sequences */ + while (stackLast >= 0) { + if (state == SEEKING_STRONG_FOR_FSI) { + /* no need for next statement, already set by default */ + /* dirProps[isolateStartStack[stackLast]] = LRI; */ + flags |= DirPropFlag(LRI); + break; + } + state = previousStateStack[stackLast]; + stackLast--; + } + /* When streaming, ignore text after the last paragraph separator */ + if ((reorderingOptions & OPTION_STREAMING) != 0) { + if (length < originalLength) + paraCount--; + } else { + paras_limit[paraCount - 1] = originalLength; + this.controlCount = controlCount; + } + /* + * For inverse bidi, default para direction is RTL if there is a strong R or AL + * at either end of the paragraph + */ + if (isDefaultLevelInverse && lastStrong == R) { + paras_level[paraCount - 1] = 1; + } + if (isDefaultLevel) { + paraLevel = paras_level[0]; + } + /* + * The following is needed to resolve the text direction for default level + * paragraphs containing no strong character + */ + for (i = 0; i < paraCount; i++) + flags |= DirPropFlagLR(paras_level[i]); + + if (orderParagraphsLTR && (flags & DirPropFlag(B)) != 0) { + flags |= DirPropFlag(L); + } + } + + /* determine the paragraph level at position index */ + byte GetParaLevelAt(int pindex) { + if (defaultParaLevel == 0 || pindex < paras_limit[0]) + return paraLevel; + int i; + for (i = 1; i < paraCount; i++) + if (pindex < paras_limit[i]) + break; + if (i >= paraCount) + i = paraCount - 1; + return paras_level[i]; + } + + /* Functions for handling paired brackets ----------------------------------- */ + + /* + * In the isoRuns array, the first entry is used for text outside of any isolate + * sequence. Higher entries are used for each more deeply nested isolate + * sequence. isoRunLast is the index of the last used entry. The openings array + * is used to note the data of opening brackets not yet matched by a closing + * bracket, or matched but still susceptible to change level. Each isoRun entry + * contains the index of the first and one-after-last openings entries for + * pending opening brackets it contains. The next openings entry to use is the + * one-after-last of the most deeply nested isoRun entry. isoRun entries also + * contain their current embedding level and the last encountered strong + * character, since these will be needed to resolve the level of paired + * brackets. + */ + + private void bracketInit(BracketData bd) { + bd.isoRunLast = 0; + bd.isoRuns[0] = new IsoRun(); + bd.isoRuns[0].start = 0; + bd.isoRuns[0].limit = 0; + bd.isoRuns[0].level = GetParaLevelAt(0); + bd.isoRuns[0].lastStrong = bd.isoRuns[0].lastBase = bd.isoRuns[0].contextDir = (byte) (GetParaLevelAt(0) & 1); + bd.isoRuns[0].contextPos = 0; + bd.openings = new Opening[SIMPLE_PARAS_COUNT]; + bd.isNumbersSpecial = reorderingMode == REORDER_NUMBERS_SPECIAL + || reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL; + } + + /* paragraph boundary */ + private void bracketProcessB(BracketData bd, byte level) { + bd.isoRunLast = 0; + bd.isoRuns[0].limit = 0; + bd.isoRuns[0].level = level; + bd.isoRuns[0].lastStrong = bd.isoRuns[0].lastBase = bd.isoRuns[0].contextDir = (byte) (level & 1); + bd.isoRuns[0].contextPos = 0; + } + + /* LRE, LRO, RLE, RLO, PDF */ + private void bracketProcessBoundary(BracketData bd, int lastCcPos, byte contextLevel, byte embeddingLevel) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + if ((DirPropFlag(dirProps[lastCcPos]) & MASK_ISO) != 0) /* after an isolate */ + return; + if (NoOverride(embeddingLevel) > NoOverride(contextLevel)) /* not a PDF */ + contextLevel = embeddingLevel; + pLastIsoRun.limit = pLastIsoRun.start; + pLastIsoRun.level = embeddingLevel; + pLastIsoRun.lastStrong = pLastIsoRun.lastBase = pLastIsoRun.contextDir = (byte) (contextLevel & 1); + pLastIsoRun.contextPos = lastCcPos; + } + + /* LRI or RLI */ + private void bracketProcessLRI_RLI(BracketData bd, byte level) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + short lastLimit; + pLastIsoRun.lastBase = ON; + lastLimit = pLastIsoRun.limit; + bd.isoRunLast++; + pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + if (pLastIsoRun == null) + pLastIsoRun = bd.isoRuns[bd.isoRunLast] = new IsoRun(); + pLastIsoRun.start = pLastIsoRun.limit = lastLimit; + pLastIsoRun.level = level; + pLastIsoRun.lastStrong = pLastIsoRun.lastBase = pLastIsoRun.contextDir = (byte) (level & 1); + pLastIsoRun.contextPos = 0; + } + + /* PDI */ + private void bracketProcessPDI(BracketData bd) { + IsoRun pLastIsoRun; + bd.isoRunLast--; + pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + pLastIsoRun.lastBase = ON; + } + + /* newly found opening bracket: create an openings entry */ + private void bracketAddOpening(BracketData bd, char match, int position) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + Opening pOpening; + if (pLastIsoRun.limit >= bd.openings.length) { /* no available new entry */ + Opening[] saveOpenings = bd.openings; + int count; + try { + count = bd.openings.length; + bd.openings = new Opening[count * 2]; + } catch (Exception e) { + throw new OutOfMemoryError("Failed to allocate memory for openings"); + } + System.arraycopy(saveOpenings, 0, bd.openings, 0, count); + } + pOpening = bd.openings[pLastIsoRun.limit]; + if (pOpening == null) + pOpening = bd.openings[pLastIsoRun.limit] = new Opening(); + pOpening.position = position; + pOpening.match = match; + pOpening.contextDir = pLastIsoRun.contextDir; + pOpening.contextPos = pLastIsoRun.contextPos; + pOpening.flags = 0; + pLastIsoRun.limit++; + } + + /* + * change N0c1 to N0c2 when a preceding bracket is assigned the embedding level + */ + private void fixN0c(BracketData bd, int openingIndex, int newPropPosition, byte newProp) { + /* This function calls itself recursively */ + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + Opening qOpening; + int k, openingPosition, closingPosition; + for (k = openingIndex + 1; k < pLastIsoRun.limit; k++) { + qOpening = bd.openings[k]; + if (qOpening.match >= 0) /* not an N0c match */ + continue; + if (newPropPosition < qOpening.contextPos) + break; + if (newPropPosition >= qOpening.position) + continue; + if (newProp == qOpening.contextDir) + break; + openingPosition = qOpening.position; + dirProps[openingPosition] = newProp; + closingPosition = -(qOpening.match); + dirProps[closingPosition] = newProp; + qOpening.match = 0; /* prevent further changes */ + fixN0c(bd, k, openingPosition, newProp); + fixN0c(bd, k, closingPosition, newProp); + } + } + + /* process closing bracket; return L or R if N0b or N0c, ON if N0d */ + private byte bracketProcessClosing(BracketData bd, int openIdx, int position) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + Opening pOpening, qOpening; + byte direction; + boolean stable; + byte newProp; + pOpening = bd.openings[openIdx]; + direction = (byte) (pLastIsoRun.level & 1); + stable = true; /* assume stable until proved otherwise */ + + /* + * The stable flag is set when brackets are paired and their level is resolved + * and cannot be changed by what will be found later in the source string. An + * unstable match can occur only when applying N0c, where the resolved level + * depends on the preceding context, and this context may be affected by text + * occurring later. Example: RTL paragraph containing: abc[(latin) HEBREW] When + * the closing parenthesis is encountered, it appears that N0c1 must be applied + * since 'abc' sets an opposite direction context and both parentheses receive + * level 2. However, when the closing square bracket is processed, N0b applies + * because of 'HEBREW' being included within the brackets, thus the square + * brackets are treated like R and receive level 1. However, this changes the + * preceding context of the opening parenthesis, and it now appears that N0c2 + * must be applied to the parentheses rather than N0c1. + */ + + if ((direction == 0 && (pOpening.flags & FOUND_L) > 0) + || (direction == 1 && (pOpening.flags & FOUND_R) > 0)) { /* N0b */ + newProp = direction; + } else if ((pOpening.flags & (FOUND_L | FOUND_R)) != 0) { /* N0c */ + /* + * it is stable if there is no preceding text or in conditions too complicated + * and not worth checking + */ + stable = (openIdx == pLastIsoRun.start); + if (direction != pOpening.contextDir) + newProp = pOpening.contextDir; /* N0c1 */ + else + newProp = direction; /* N0c2 */ + } else { + /* forget this and any brackets nested within this pair */ + pLastIsoRun.limit = (short) openIdx; + return ON; /* N0d */ + } + dirProps[pOpening.position] = newProp; + dirProps[position] = newProp; + /* Update nested N0c pairs that may be affected */ + fixN0c(bd, openIdx, pOpening.position, newProp); + if (stable) { + pLastIsoRun.limit = (short) openIdx; /* forget any brackets nested within this pair */ + /* remove lower located synonyms if any */ + while (pLastIsoRun.limit > pLastIsoRun.start + && bd.openings[pLastIsoRun.limit - 1].position == pOpening.position) + pLastIsoRun.limit--; + } else { + int k; + pOpening.match = -position; + /* neutralize lower located synonyms if any */ + k = openIdx - 1; + while (k >= pLastIsoRun.start && bd.openings[k].position == pOpening.position) + bd.openings[k--].match = 0; + /* + * neutralize any unmatched opening between the current pair; this will also + * neutralize higher located synonyms if any + */ + for (k = openIdx + 1; k < pLastIsoRun.limit; k++) { + qOpening = bd.openings[k]; + if (qOpening.position >= position) + break; + if (qOpening.match > 0) + qOpening.match = 0; + } + } + return newProp; + } + + /* handle strong characters, digits and candidates for closing brackets */ + private void bracketProcessChar(BracketData bd, int position) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + byte dirProp, newProp; + byte level; + dirProp = dirProps[position]; + if (dirProp == ON) { + char c, match; + int idx; + /* + * First see if it is a matching closing bracket. Hopefully, this is more + * efficient than checking if it is a closing bracket at all + */ + c = text[position]; + for (idx = pLastIsoRun.limit - 1; idx >= pLastIsoRun.start; idx--) { + if (bd.openings[idx].match != c) + continue; + /* We have a match */ + newProp = bracketProcessClosing(bd, idx, position); + if (newProp == ON) { /* N0d */ + c = 0; /* prevent handling as an opening */ + break; + } + pLastIsoRun.lastBase = ON; + pLastIsoRun.contextDir = newProp; + pLastIsoRun.contextPos = position; + level = levels[position]; + if ((level & LEVEL_OVERRIDE) != 0) { /* X4, X5 */ + short flag; + int i; + newProp = (byte) (level & 1); + pLastIsoRun.lastStrong = newProp; + flag = (short) DirPropFlag(newProp); + for (i = pLastIsoRun.start; i < idx; i++) + bd.openings[i].flags |= flag; + /* matching brackets are not overridden by LRO/RLO */ + levels[position] &= ~LEVEL_OVERRIDE; + } + /* matching brackets are not overridden by LRO/RLO */ + levels[bd.openings[idx].position] &= ~LEVEL_OVERRIDE; + return; + } + /* + * We get here only if the ON character is not a matching closing bracket or it + * is a case of N0d + */ + /* Now see if it is an opening bracket */ + if (c != 0) { + match = (char) UCharacter.getBidiPairedBracket(c); /* get the matching char */ + } else { + match = 0; + } + if (match != c && /* has a matching char */ + UCharacter.getIntPropertyValue(c, BIDI_PAIRED_BRACKET_TYPE) == + /* opening bracket */ BidiPairedBracketType.OPEN) { + /* + * special case: process synonyms create an opening entry for each synonym + */ + if (match == 0x232A) { /* RIGHT-POINTING ANGLE BRACKET */ + bracketAddOpening(bd, (char) 0x3009, position); + } else if (match == 0x3009) { /* RIGHT ANGLE BRACKET */ + bracketAddOpening(bd, (char) 0x232A, position); + } + bracketAddOpening(bd, match, position); + } + } + level = levels[position]; + if ((level & LEVEL_OVERRIDE) != 0) { /* X4, X5 */ + newProp = (byte) (level & 1); + if (dirProp != S && dirProp != WS && dirProp != ON) + dirProps[position] = newProp; + pLastIsoRun.lastBase = newProp; + pLastIsoRun.lastStrong = newProp; + pLastIsoRun.contextDir = newProp; + pLastIsoRun.contextPos = position; + } else if (dirProp <= R || dirProp == AL) { + newProp = DirFromStrong(dirProp); + pLastIsoRun.lastBase = dirProp; + pLastIsoRun.lastStrong = dirProp; + pLastIsoRun.contextDir = newProp; + pLastIsoRun.contextPos = position; + } else if (dirProp == EN) { + pLastIsoRun.lastBase = EN; + if (pLastIsoRun.lastStrong == L) { + newProp = L; /* W7 */ + if (!bd.isNumbersSpecial) + dirProps[position] = ENL; + pLastIsoRun.contextDir = L; + pLastIsoRun.contextPos = position; + } else { + newProp = R; /* N0 */ + if (pLastIsoRun.lastStrong == AL) + dirProps[position] = AN; /* W2 */ + else + dirProps[position] = ENR; + pLastIsoRun.contextDir = R; + pLastIsoRun.contextPos = position; + } + } else if (dirProp == AN) { + newProp = R; /* N0 */ + pLastIsoRun.lastBase = AN; + pLastIsoRun.contextDir = R; + pLastIsoRun.contextPos = position; + } else if (dirProp == NSM) { + /* + * if the last real char was ON, change NSM to ON so that it will stay ON even + * if the last real char is a bracket which may be changed to L or R + */ + newProp = pLastIsoRun.lastBase; + if (newProp == ON) + dirProps[position] = newProp; + } else { + newProp = dirProp; + pLastIsoRun.lastBase = dirProp; + } + if (newProp <= R || newProp == AL) { + int i; + short flag = (short) DirPropFlag(DirFromStrong(newProp)); + for (i = pLastIsoRun.start; i < pLastIsoRun.limit; i++) + if (position > bd.openings[i].position) + bd.openings[i].flags |= flag; + } + } + + /* perform (X1)..(X9) ------------------------------------------------------- */ + + /* determine if the text is mixed-directional or single-directional */ + private byte directionFromFlags() { + + /* if the text contains AN and neutrals, then some neutrals may become RTL */ + if (!((flags & MASK_RTL) != 0 || ((flags & DirPropFlag(AN)) != 0 && (flags & MASK_POSSIBLE_N) != 0))) { + return LTR; + } else if ((flags & MASK_LTR) == 0) { + return RTL; + } else { + return MIXED; + } + } + + /* + * Resolve the explicit levels as specified by explicit embedding codes. + * Recalculate the flags to have them reflect the real properties after taking + * the explicit embeddings into account. + * + * The BiDi algorithm is designed to result in the same behavior whether + * embedding levels are externally specified (from "styled text", supposedly the + * preferred method) or set by explicit embedding codes (LRx, RLx, PDF, FSI, + * PDI) in the plain text. That is why (X9) instructs to remove all not-isolate + * explicit codes (and BN). However, in a real implementation, the removal of + * these codes and their index positions in the plain text is undesirable since + * it would result in reallocated, reindexed text. Instead, this implementation + * leaves the codes in there and just ignores them in the subsequent processing. + * In order to get the same reordering behavior, positions with a BN or a + * not-isolate explicit embedding code just get the same level assigned as the + * last "real" character. + * + * Some implementations, not this one, then overwrite some of these + * directionality properties at "real" same-level-run boundaries by L or R codes + * so that the resolution of weak types can be performed on the entire paragraph + * at once instead of having to parse it once more and perform that resolution + * on same-level-runs. This limits the scope of the implicit rules in + * effectively the same way as the run limits. + * + * Instead, this implementation does not modify these codes, except for paired + * brackets whose properties (ON) may be replaced by L or R. On one hand, the + * paragraph has to be scanned for same-level-runs, but on the other hand, this + * saves another loop to reset these codes, or saves making and modifying a copy + * of dirProps[]. + * + * + * Note that (Pn) and (Xn) changed significantly from version 4 of the BiDi + * algorithm. + * + * + * Handling the stack of explicit levels (Xn): + * + * With the BiDi stack of explicit levels, as pushed with each LRE, RLE, LRO, + * RLO, LRI, RLI and FSI and popped with each PDF and PDI, the explicit level + * must never exceed MAX_EXPLICIT_LEVEL. + * + * In order to have a correct push-pop semantics even in the case of overflows, + * overflow counters and a valid isolate counter are used as described in UAX#9 + * section 3.3.2 "Explicit Levels and Directions". + * + * This implementation assumes that MAX_EXPLICIT_LEVEL is odd. + * + * Returns the direction + * + */ + private byte resolveExplicitLevels() { + int i = 0; + byte dirProp; + byte level = GetParaLevelAt(0); + byte dirct; + isolateCount = 0; + + /* determine if the text is mixed-directional or single-directional */ + dirct = directionFromFlags(); + + /* we may not need to resolve any explicit levels */ + if (dirct != MIXED) { + /* not mixed directionality: levels don't matter - trailingWSStart will be 0 */ + return dirct; + } + + if (reorderingMode > REORDER_LAST_LOGICAL_TO_VISUAL) { + /* inverse BiDi: mixed, but all characters are at the same embedding level */ + /* set all levels to the paragraph level */ + int paraIndex, start, limit; + for (paraIndex = 0; paraIndex < paraCount; paraIndex++) { + if (paraIndex == 0) + start = 0; + else + start = paras_limit[paraIndex - 1]; + limit = paras_limit[paraIndex]; + level = paras_level[paraIndex]; + for (i = start; i < limit; i++) + levels[i] = level; + } + return dirct; /* no bracket matching for inverse BiDi */ + } + if ((flags & (MASK_EXPLICIT | MASK_ISO)) == 0) { + /* no embeddings, set all levels to the paragraph level */ + /* we still have to perform bracket matching */ + int paraIndex, start, limit; + BracketData bracketData = new BracketData(); + bracketInit(bracketData); + for (paraIndex = 0; paraIndex < paraCount; paraIndex++) { + if (paraIndex == 0) + start = 0; + else + start = paras_limit[paraIndex - 1]; + limit = paras_limit[paraIndex]; + level = paras_level[paraIndex]; + for (i = start; i < limit; i++) { + levels[i] = level; + dirProp = dirProps[i]; + if (dirProp == BN) + continue; + if (dirProp == B) { + if ((i + 1) < length) { + if (text[i] == CR && text[i + 1] == LF) + continue; /* skip CR when followed by LF */ + bracketProcessB(bracketData, level); + } + continue; + } + bracketProcessChar(bracketData, i); + } + } + return dirct; + } + /* continue to perform (Xn) */ + + /* + * (X1) level is set for all codes, embeddingLevel keeps track of the push/pop + * operations + */ + /* + * both variables may carry the LEVEL_OVERRIDE flag to indicate the override + * status + */ + byte embeddingLevel = level, newLevel; + byte previousLevel = level; /* previous level for regular (not CC) characters */ + int lastCcPos = 0; /* index of last effective LRx,RLx, PDx */ + + /* + * The following stack remembers the embedding level and the ISOLATE flag of + * level runs. stackLast points to its current entry. + */ + short[] stack = new short[MAX_EXPLICIT_LEVEL + 2]; /* + * we never push anything >= MAX_EXPLICIT_LEVEL but we need + * one more entry as base + */ + int stackLast = 0; + int overflowIsolateCount = 0; + int overflowEmbeddingCount = 0; + int validIsolateCount = 0; + BracketData bracketData = new BracketData(); + bracketInit(bracketData); + stack[0] = level; /* initialize base entry to para level, no override, no isolate */ + + /* recalculate the flags */ + flags = 0; + + for (i = 0; i < length; i++) { + dirProp = dirProps[i]; + switch (dirProp) { + case LRE: + case RLE: + case LRO: + case RLO: + /* (X2, X3, X4, X5) */ + flags |= DirPropFlag(BN); + levels[i] = previousLevel; + if (dirProp == LRE || dirProp == LRO) { + /* least greater even level */ + newLevel = (byte) ((embeddingLevel + 2) & ~(LEVEL_OVERRIDE | 1)); + } else { + /* least greater odd level */ + newLevel = (byte) ((NoOverride(embeddingLevel) + 1) | 1); + } + if (newLevel <= MAX_EXPLICIT_LEVEL && overflowIsolateCount == 0 && overflowEmbeddingCount == 0) { + lastCcPos = i; + embeddingLevel = newLevel; + if (dirProp == LRO || dirProp == RLO) + embeddingLevel |= LEVEL_OVERRIDE; + stackLast++; + stack[stackLast] = embeddingLevel; + /* + * we don't need to set LEVEL_OVERRIDE off for LRE and RLE since this has + * already been done for newLevel which is the source for embeddingLevel. + */ + } else { + if (overflowIsolateCount == 0) + overflowEmbeddingCount++; + } + break; + case PDF: + /* (X7) */ + flags |= DirPropFlag(BN); + levels[i] = previousLevel; + /* handle all the overflow cases first */ + if (overflowIsolateCount > 0) { + break; + } + if (overflowEmbeddingCount > 0) { + overflowEmbeddingCount--; + break; + } + if (stackLast > 0 && stack[stackLast] < ISOLATE) { /* not an isolate entry */ + lastCcPos = i; + stackLast--; + embeddingLevel = (byte) stack[stackLast]; + } + break; + case LRI: + case RLI: + flags |= DirPropFlag(ON) | DirPropFlagLR(embeddingLevel); + levels[i] = NoOverride(embeddingLevel); + if (NoOverride(embeddingLevel) != NoOverride(previousLevel)) { + bracketProcessBoundary(bracketData, lastCcPos, previousLevel, embeddingLevel); + flags |= DirPropFlagMultiRuns; + } + previousLevel = embeddingLevel; + /* (X5a, X5b) */ + if (dirProp == LRI) + /* least greater even level */ + newLevel = (byte) ((embeddingLevel + 2) & ~(LEVEL_OVERRIDE | 1)); + else + /* least greater odd level */ + newLevel = (byte) ((NoOverride(embeddingLevel) + 1) | 1); + if (newLevel <= MAX_EXPLICIT_LEVEL && overflowIsolateCount == 0 && overflowEmbeddingCount == 0) { + flags |= DirPropFlag(dirProp); + lastCcPos = i; + validIsolateCount++; + if (validIsolateCount > isolateCount) + isolateCount = validIsolateCount; + embeddingLevel = newLevel; + /* + * we can increment stackLast without checking because newLevel will exceed + * UBIDI_MAX_EXPLICIT_LEVEL before stackLast overflows + */ + stackLast++; + stack[stackLast] = (short) (embeddingLevel + ISOLATE); + bracketProcessLRI_RLI(bracketData, embeddingLevel); + } else { + /* make it WS so that it is handled by adjustWSLevels() */ + dirProps[i] = WS; + overflowIsolateCount++; + } + break; + case PDI: + if (NoOverride(embeddingLevel) != NoOverride(previousLevel)) { + bracketProcessBoundary(bracketData, lastCcPos, previousLevel, embeddingLevel); + flags |= DirPropFlagMultiRuns; + } + /* (X6a) */ + if (overflowIsolateCount > 0) { + overflowIsolateCount--; + /* make it WS so that it is handled by adjustWSLevels() */ + dirProps[i] = WS; + } else if (validIsolateCount > 0) { + flags |= DirPropFlag(PDI); + lastCcPos = i; + overflowEmbeddingCount = 0; + while (stack[stackLast] < ISOLATE) /* pop embedding entries */ + stackLast--; /* until the last isolate entry */ + stackLast--; /* pop also the last isolate entry */ + validIsolateCount--; + bracketProcessPDI(bracketData); + } else + /* make it WS so that it is handled by adjustWSLevels() */ + dirProps[i] = WS; + embeddingLevel = (byte) (stack[stackLast] & ~ISOLATE); + flags |= DirPropFlag(ON) | DirPropFlagLR(embeddingLevel); + previousLevel = embeddingLevel; + levels[i] = NoOverride(embeddingLevel); + break; + case B: + flags |= DirPropFlag(B); + levels[i] = GetParaLevelAt(i); + if ((i + 1) < length) { + if (text[i] == CR && text[i + 1] == LF) + break; /* skip CR when followed by LF */ + overflowEmbeddingCount = overflowIsolateCount = 0; + validIsolateCount = 0; + stackLast = 0; + previousLevel = embeddingLevel = GetParaLevelAt(i + 1); + stack[0] = embeddingLevel; /* initialize base entry to para level, no override, no isolate */ + bracketProcessB(bracketData, embeddingLevel); + } + break; + case BN: + /* BN, LRE, RLE, and PDF are supposed to be removed (X9) */ + /* they will get their levels set correctly in adjustWSLevels() */ + levels[i] = previousLevel; + flags |= DirPropFlag(BN); + break; + default: + /* all other types are normal characters and get the "real" level */ + if (NoOverride(embeddingLevel) != NoOverride(previousLevel)) { + bracketProcessBoundary(bracketData, lastCcPos, previousLevel, embeddingLevel); + flags |= DirPropFlagMultiRuns; + if ((embeddingLevel & LEVEL_OVERRIDE) != 0) + flags |= DirPropFlagO(embeddingLevel); + else + flags |= DirPropFlagE(embeddingLevel); + } + previousLevel = embeddingLevel; + levels[i] = embeddingLevel; + bracketProcessChar(bracketData, i); + /* the dirProp may have been changed in bracketProcessChar() */ + flags |= DirPropFlag(dirProps[i]); + break; + } + } + if ((flags & MASK_EMBEDDING) != 0) { + flags |= DirPropFlagLR(paraLevel); + } + if (orderParagraphsLTR && (flags & DirPropFlag(B)) != 0) { + flags |= DirPropFlag(L); + } + /* again, determine if the text is mixed-directional or single-directional */ + dirct = directionFromFlags(); + + return dirct; + } + + /* + * Use a pre-specified embedding levels array: + * + * Adjust the directional properties for overrides (->LEVEL_OVERRIDE), ignore + * all explicit codes (X9), and check all the preset levels. + * + * Recalculate the flags to have them reflect the real properties after taking + * the explicit embeddings into account. + */ + private byte checkExplicitLevels() { + byte dirProp; + int i; + int isolateCount = 0; + + this.flags = 0; /* collect all directionalities in the text */ + byte level; + this.isolateCount = 0; + + for (i = 0; i < length; ++i) { + if (levels[i] == 0) { + levels[i] = paraLevel; + } + + // for backward compatibility + if (MAX_EXPLICIT_LEVEL < (levels[i] & 0x7f)) { + if ((levels[i] & LEVEL_OVERRIDE) != 0) { + levels[i] = (byte) (paraLevel | LEVEL_OVERRIDE); + } else { + levels[i] = paraLevel; + } + } + + level = levels[i]; + dirProp = dirProps[i]; + if (dirProp == LRI || dirProp == RLI) { + isolateCount++; + if (isolateCount > this.isolateCount) + this.isolateCount = isolateCount; + } else if (dirProp == PDI) { + isolateCount--; + } else if (dirProp == B) { + isolateCount = 0; + } + if ((level & LEVEL_OVERRIDE) != 0) { + /* keep the override flag in levels[i] but adjust the flags */ + level &= ~LEVEL_OVERRIDE; /* make the range check below simpler */ + flags |= DirPropFlagO(level); + } else { + /* set the flags */ + flags |= DirPropFlagE(level) | DirPropFlag(dirProp); + } + if ((level < GetParaLevelAt(i) && !((0 == level) && (dirProp == B))) || (MAX_EXPLICIT_LEVEL < level)) { + /* level out of bounds */ + throw new IllegalArgumentException("level " + level + " out of bounds at " + i); + } + } + if ((flags & MASK_EMBEDDING) != 0) { + flags |= DirPropFlagLR(paraLevel); + } + /* determine if the text is mixed-directional or single-directional */ + return directionFromFlags(); + } + + /*********************************************************************/ + /* The Properties state machine table */ + /*********************************************************************/ + /* */ + /* All table cells are 8 bits: */ + /* bits 0..4: next state */ + /* bits 5..7: action to perform (if > 0) */ + /* */ + /* Cells may be of format "n" where n represents the next state */ + /* (except for the rightmost column). */ + /* Cells may also be of format "_(x,y)" where x represents an action */ + /* to perform and y represents the next state. */ + /* */ + /*********************************************************************/ + + /* Definitions and type for properties state tables */ + /*********************************************************************/ + private static final int IMPTABPROPS_COLUMNS = 16; + private static final int IMPTABPROPS_RES = IMPTABPROPS_COLUMNS - 1; + + private static short GetStateProps(short cell) { + return (short) (cell & 0x1f); + } + + private static short GetActionProps(short cell) { + return (short) (cell >> 5); + } + + private static final short groupProp[] = /* dirProp regrouped */ + { + /* + * L R EN ES ET AN CS B S WS ON LRE LRO AL RLE RLO PDF NSM BN FSI LRI RLI PDI + * ENL ENR + */ + 0, 1, 2, 7, 8, 3, 9, 6, 5, 4, 4, 10, 10, 12, 10, 10, 10, 11, 10, 4, 4, 4, 4, 13, 14 }; + private static final short _L = 0; + private static final short _R = 1; + private static final short _EN = 2; + private static final short _AN = 3; + private static final short _ON = 4; + private static final short _S = 5; + private static final short _B = 6; /* reduced dirProp */ + + /*********************************************************************/ + /* */ + /* PROPERTIES STATE TABLE */ + /* */ + /* In table impTabProps, */ + /* - the ON column regroups ON and WS, FSI, RLI, LRI and PDI */ + /* - the BN column regroups BN, LRE, RLE, LRO, RLO, PDF */ + /* - the Res column is the reduced property assigned to a run */ + /* */ + /* Action 1: process current run1, init new run1 */ + /* 2: init new run2 */ + /* 3: process run1, process run2, init new run1 */ + /* 4: process run1, set run1=run2, init new run2 */ + /* */ + /* Notes: */ + /* 1) This table is used in resolveImplicitLevels(). */ + /* 2) This table triggers actions when there is a change in the Bidi */ + /* property of incoming characters (action 1). */ + /* 3) Most such property sequences are processed immediately (in */ + /* fact, passed to processPropertySeq(). */ + /* 4) However, numbers are assembled as one sequence. This means */ + /* that undefined situations (like CS following digits, until */ + /* it is known if the next char will be a digit) are held until */ + /* following chars define them. */ + /* Example: digits followed by CS, then comes another CS or ON; */ + /* the digits will be processed, then the CS assigned */ + /* as the start of an ON sequence (action 3). */ + /* 5) There are cases where more than one sequence must be */ + /* processed, for instance digits followed by CS followed by L: */ + /* the digits must be processed as one sequence, and the CS */ + /* must be processed as an ON sequence, all this before starting */ + /* assembling chars for the opening L sequence. */ + /* */ + /* */ + private static final short impTabProps[][] = { + /* L, R, EN, AN, ON, S, B, ES, ET, CS, BN, NSM, AL, ENL, ENR, Res */ + /* 0 Init */ { 1, 2, 4, 5, 7, 15, 17, 7, 9, 7, 0, 7, 3, 18, 21, _ON }, + /* 1 L */ { 1, 32 + 2, 32 + 4, 32 + 5, 32 + 7, 32 + 15, 32 + 17, 32 + 7, 32 + 9, 32 + 7, 1, 1, 32 + 3, + 32 + 18, 32 + 21, _L }, + /* 2 R */ { 32 + 1, 2, 32 + 4, 32 + 5, 32 + 7, 32 + 15, 32 + 17, 32 + 7, 32 + 9, 32 + 7, 2, 2, 32 + 3, + 32 + 18, 32 + 21, _R }, + /* 3 AL */ { 32 + 1, 32 + 2, 32 + 6, 32 + 6, 32 + 8, 32 + 16, 32 + 17, 32 + 8, 32 + 8, 32 + 8, 3, 3, 3, + 32 + 18, 32 + 21, _R }, + /* 4 EN */ { 32 + 1, 32 + 2, 4, 32 + 5, 32 + 7, 32 + 15, 32 + 17, 64 + 10, 11, 64 + 10, 4, 4, 32 + 3, 18, + 21, _EN }, + /* 5 AN */ { 32 + 1, 32 + 2, 32 + 4, 5, 32 + 7, 32 + 15, 32 + 17, 32 + 7, 32 + 9, 64 + 12, 5, 5, 32 + 3, + 32 + 18, 32 + 21, _AN }, + /* 6 AL:EN/AN */ { 32 + 1, 32 + 2, 6, 6, 32 + 8, 32 + 16, 32 + 17, 32 + 8, 32 + 8, 64 + 13, 6, 6, 32 + 3, + 18, 21, _AN }, + /* 7 ON */ { 32 + 1, 32 + 2, 32 + 4, 32 + 5, 7, 32 + 15, 32 + 17, 7, 64 + 14, 7, 7, 7, 32 + 3, 32 + 18, + 32 + 21, _ON }, + /* 8 AL:ON */ { 32 + 1, 32 + 2, 32 + 6, 32 + 6, 8, 32 + 16, 32 + 17, 8, 8, 8, 8, 8, 32 + 3, 32 + 18, + 32 + 21, _ON }, + /* 9 ET */ { 32 + 1, 32 + 2, 4, 32 + 5, 7, 32 + 15, 32 + 17, 7, 9, 7, 9, 9, 32 + 3, 18, 21, _ON }, + /* 10 EN+ES/CS */ { 96 + 1, 96 + 2, 4, 96 + 5, 128 + 7, 96 + 15, 96 + 17, 128 + 7, 128 + 14, 128 + 7, 10, + 128 + 7, 96 + 3, 18, 21, _EN }, + /* 11 EN+ET */ { 32 + 1, 32 + 2, 4, 32 + 5, 32 + 7, 32 + 15, 32 + 17, 32 + 7, 11, 32 + 7, 11, 11, 32 + 3, + 18, 21, _EN }, + /* 12 AN+CS */ { 96 + 1, 96 + 2, 96 + 4, 5, 128 + 7, 96 + 15, 96 + 17, 128 + 7, 128 + 14, 128 + 7, 12, + 128 + 7, 96 + 3, 96 + 18, 96 + 21, _AN }, + /* 13 AL:EN/AN+CS */ { 96 + 1, 96 + 2, 6, 6, 128 + 8, 96 + 16, 96 + 17, 128 + 8, 128 + 8, 128 + 8, 13, + 128 + 8, 96 + 3, 18, 21, _AN }, + /* 14 ON+ET */ { 32 + 1, 32 + 2, 128 + 4, 32 + 5, 7, 32 + 15, 32 + 17, 7, 14, 7, 14, 14, 32 + 3, 128 + 18, + 128 + 21, _ON }, + /* 15 S */ { 32 + 1, 32 + 2, 32 + 4, 32 + 5, 32 + 7, 15, 32 + 17, 32 + 7, 32 + 9, 32 + 7, 15, 32 + 7, + 32 + 3, 32 + 18, 32 + 21, _S }, + /* 16 AL:S */ { 32 + 1, 32 + 2, 32 + 6, 32 + 6, 32 + 8, 16, 32 + 17, 32 + 8, 32 + 8, 32 + 8, 16, 32 + 8, + 32 + 3, 32 + 18, 32 + 21, _S }, + /* 17 B */ { 32 + 1, 32 + 2, 32 + 4, 32 + 5, 32 + 7, 32 + 15, 17, 32 + 7, 32 + 9, 32 + 7, 17, 32 + 7, + 32 + 3, 32 + 18, 32 + 21, _B }, + /* 18 ENL */ { 32 + 1, 32 + 2, 18, 32 + 5, 32 + 7, 32 + 15, 32 + 17, 64 + 19, 20, 64 + 19, 18, 18, 32 + 3, + 18, 21, _L }, + /* 19 ENL+ES/CS */ { 96 + 1, 96 + 2, 18, 96 + 5, 128 + 7, 96 + 15, 96 + 17, 128 + 7, 128 + 14, 128 + 7, 19, + 128 + 7, 96 + 3, 18, 21, _L }, + /* 20 ENL+ET */ { 32 + 1, 32 + 2, 18, 32 + 5, 32 + 7, 32 + 15, 32 + 17, 32 + 7, 20, 32 + 7, 20, 20, 32 + 3, + 18, 21, _L }, + /* 21 ENR */ { 32 + 1, 32 + 2, 21, 32 + 5, 32 + 7, 32 + 15, 32 + 17, 64 + 22, 23, 64 + 22, 21, 21, 32 + 3, + 18, 21, _AN }, + /* 22 ENR+ES/CS */ { 96 + 1, 96 + 2, 21, 96 + 5, 128 + 7, 96 + 15, 96 + 17, 128 + 7, 128 + 14, 128 + 7, 22, + 128 + 7, 96 + 3, 18, 21, _AN }, + /* 23 ENR+ET */ { 32 + 1, 32 + 2, 21, 32 + 5, 32 + 7, 32 + 15, 32 + 17, 32 + 7, 23, 32 + 7, 23, 23, 32 + 3, + 18, 21, _AN } }; + + /*********************************************************************/ + /* The levels state machine tables */ + /*********************************************************************/ + /* */ + /* All table cells are 8 bits: */ + /* bits 0..3: next state */ + /* bits 4..7: action to perform (if > 0) */ + /* */ + /* Cells may be of format "n" where n represents the next state */ + /* (except for the rightmost column). */ + /* Cells may also be of format "_(x,y)" where x represents an action */ + /* to perform and y represents the next state. */ + /* */ + /* This format limits each table to 16 states each and to 15 actions. */ + /* */ + /*********************************************************************/ + /* Definitions and type for levels state tables */ + /*********************************************************************/ + private static final int IMPTABLEVELS_COLUMNS = _B + 2; + private static final int IMPTABLEVELS_RES = IMPTABLEVELS_COLUMNS - 1; + + private static short GetState(byte cell) { + return (short) (cell & 0x0f); + } + + private static short GetAction(byte cell) { + return (short) (cell >> 4); + } + + private static class ImpTabPair { + byte[][][] imptab; + short[][] impact; + + ImpTabPair(byte[][] table1, byte[][] table2, short[] act1, short[] act2) { + imptab = new byte[][][] { table1, table2 }; + impact = new short[][] { act1, act2 }; + } + } + + /*********************************************************************/ + /* */ + /* LEVELS STATE TABLES */ + /* */ + /* In all levels state tables, */ + /* - state 0 is the initial state */ + /* - the Res column is the increment to add to the text level */ + /* for this property sequence. */ + /* */ + /* The impact arrays for each table of a pair map the local action */ + /* numbers of the table to the total list of actions. For instance, */ + /* action 2 in a given table corresponds to the action number which */ + /* appears in entry [2] of the impact array for that table. */ + /* The first entry of all impact arrays must be 0. */ + /* */ + /* Action 1: init conditional sequence */ + /* 2: prepend conditional sequence to current sequence */ + /* 3: set ON sequence to new level - 1 */ + /* 4: init EN/AN/ON sequence */ + /* 5: fix EN/AN/ON sequence followed by R */ + /* 6: set previous level sequence to level 2 */ + /* */ + /* Notes: */ + /* 1) These tables are used in processPropertySeq(). The input */ + /* is property sequences as determined by resolveImplicitLevels. */ + /* 2) Most such property sequences are processed immediately */ + /* (levels are assigned). */ + /* 3) However, some sequences cannot be assigned a final level till */ + /* one or more following sequences are received. For instance, */ + /* ON following an R sequence within an even-level paragraph. */ + /* If the following sequence is R, the ON sequence will be */ + /* assigned basic run level+1, and so will the R sequence. */ + /* 4) S is generally handled like ON, since its level will be fixed */ + /* to paragraph level in adjustWSLevels(). */ + /* */ + + private static final byte impTabL_DEFAULT[][] = /* Even paragraph level */ + /* + * In this table, conditional sequences receive the lower possible level until + * proven otherwise. + */ + { + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 0, 1, 0, 2, 0, 0, 0, 0 }, /* 1 : R */ { 0, 1, 3, 3, 0x14, 0x14, 0, 1 }, + /* 2 : AN */ { 0, 1, 0, 2, 0x15, 0x15, 0, 2 }, /* 3 : R+EN/AN */ { 0, 1, 3, 3, 0x14, 0x14, 0, 2 }, + /* 4 : R+ON */ { 0, 0x21, 0x33, 0x33, 4, 4, 0, 0 }, + /* 5 : AN+ON */ { 0, 0x21, 0, 0x32, 5, 5, 0, 0 } }; + + private static final byte impTabR_DEFAULT[][] = /* Odd paragraph level */ + /* + * In this table, conditional sequences receive the lower possible level until + * proven otherwise. + */ + { + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 1, 0, 2, 2, 0, 0, 0, 0 }, /* 1 : L */ { 1, 0, 1, 3, 0x14, 0x14, 0, 1 }, + /* 2 : EN/AN */ { 1, 0, 2, 2, 0, 0, 0, 1 }, /* 3 : L+AN */ { 1, 0, 1, 3, 5, 5, 0, 1 }, + /* 4 : L+ON */ { 0x21, 0, 0x21, 3, 4, 4, 0, 0 }, /* 5 : L+AN+ON */ { 1, 0, 1, 3, 5, 5, 0, 0 } }; + + private static final short[] impAct0 = { 0, 1, 2, 3, 4 }; + + private static final ImpTabPair impTab_DEFAULT = new ImpTabPair(impTabL_DEFAULT, impTabR_DEFAULT, impAct0, impAct0); + + private static final byte impTabL_NUMBERS_SPECIAL[][] = { /* Even paragraph level */ + /* + * In this table, conditional sequences receive the lower possible level until + * proven otherwise. + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 0, 2, 0x11, 0x11, 0, 0, 0, 0 }, /* 1 : L+EN/AN */ { 0, 0x42, 1, 1, 0, 0, 0, 0 }, + /* 2 : R */ { 0, 2, 4, 4, 0x13, 0x13, 0, 1 }, /* 3 : R+ON */ { 0, 0x22, 0x34, 0x34, 3, 3, 0, 0 }, + /* 4 : R+EN/AN */ { 0, 2, 4, 4, 0x13, 0x13, 0, 2 } }; + private static final ImpTabPair impTab_NUMBERS_SPECIAL = new ImpTabPair(impTabL_NUMBERS_SPECIAL, impTabR_DEFAULT, + impAct0, impAct0); + + private static final byte impTabL_GROUP_NUMBERS_WITH_R[][] = { + /* + * In this table, EN/AN+ON sequences receive levels as if associated with R + * until proven that there is L or sor/eor on both sides. AN is handled like EN. + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 init */ { 0, 3, 0x11, 0x11, 0, 0, 0, 0 }, /* 1 EN/AN */ { 0x20, 3, 1, 1, 2, 0x20, 0x20, 2 }, + /* 2 EN/AN+ON */ { 0x20, 3, 1, 1, 2, 0x20, 0x20, 1 }, /* 3 R */ { 0, 3, 5, 5, 0x14, 0, 0, 1 }, + /* 4 R+ON */ { 0x20, 3, 5, 5, 4, 0x20, 0x20, 1 }, /* 5 R+EN/AN */ { 0, 3, 5, 5, 0x14, 0, 0, 2 } }; + private static final byte impTabR_GROUP_NUMBERS_WITH_R[][] = { + /* + * In this table, EN/AN+ON sequences receive levels as if associated with R + * until proven that there is L on both sides. AN is handled like EN. + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 init */ { 2, 0, 1, 1, 0, 0, 0, 0 }, /* 1 EN/AN */ { 2, 0, 1, 1, 0, 0, 0, 1 }, + /* 2 L */ { 2, 0, 0x14, 0x14, 0x13, 0, 0, 1 }, /* 3 L+ON */ { 0x22, 0, 4, 4, 3, 0, 0, 0 }, + /* 4 L+EN/AN */ { 0x22, 0, 4, 4, 3, 0, 0, 1 } }; + private static final ImpTabPair impTab_GROUP_NUMBERS_WITH_R = new ImpTabPair(impTabL_GROUP_NUMBERS_WITH_R, + impTabR_GROUP_NUMBERS_WITH_R, impAct0, impAct0); + + private static final byte impTabL_INVERSE_NUMBERS_AS_L[][] = { + /* + * This table is identical to the Default LTR table except that EN and AN are + * handled like L. + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 0, 1, 0, 0, 0, 0, 0, 0 }, /* 1 : R */ { 0, 1, 0, 0, 0x14, 0x14, 0, 1 }, + /* 2 : AN */ { 0, 1, 0, 0, 0x15, 0x15, 0, 2 }, /* 3 : R+EN/AN */ { 0, 1, 0, 0, 0x14, 0x14, 0, 2 }, + /* 4 : R+ON */ { 0x20, 1, 0x20, 0x20, 4, 4, 0x20, 1 }, + /* 5 : AN+ON */ { 0x20, 1, 0x20, 0x20, 5, 5, 0x20, 1 } }; + private static final byte impTabR_INVERSE_NUMBERS_AS_L[][] = { + /* + * This table is identical to the Default RTL table except that EN and AN are + * handled like L. + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 1, 0, 1, 1, 0, 0, 0, 0 }, /* 1 : L */ { 1, 0, 1, 1, 0x14, 0x14, 0, 1 }, + /* 2 : EN/AN */ { 1, 0, 1, 1, 0, 0, 0, 1 }, /* 3 : L+AN */ { 1, 0, 1, 1, 5, 5, 0, 1 }, + /* 4 : L+ON */ { 0x21, 0, 0x21, 0x21, 4, 4, 0, 0 }, /* 5 : L+AN+ON */ { 1, 0, 1, 1, 5, 5, 0, 0 } }; + private static final ImpTabPair impTab_INVERSE_NUMBERS_AS_L = new ImpTabPair(impTabL_INVERSE_NUMBERS_AS_L, + impTabR_INVERSE_NUMBERS_AS_L, impAct0, impAct0); + + private static final byte impTabR_INVERSE_LIKE_DIRECT[][] = { /* Odd paragraph level */ + /* + * In this table, conditional sequences receive the lower possible level until + * proven otherwise. + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 1, 0, 2, 2, 0, 0, 0, 0 }, /* 1 : L */ { 1, 0, 1, 2, 0x13, 0x13, 0, 1 }, + /* 2 : EN/AN */ { 1, 0, 2, 2, 0, 0, 0, 1 }, /* 3 : L+ON */ { 0x21, 0x30, 6, 4, 3, 3, 0x30, 0 }, + /* 4 : L+ON+AN */ { 0x21, 0x30, 6, 4, 5, 5, 0x30, 3 }, + /* 5 : L+AN+ON */ { 0x21, 0x30, 6, 4, 5, 5, 0x30, 2 }, + /* 6 : L+ON+EN */ { 0x21, 0x30, 6, 4, 3, 3, 0x30, 1 } }; + private static final short[] impAct1 = { 0, 1, 13, 14 }; + private static final ImpTabPair impTab_INVERSE_LIKE_DIRECT = new ImpTabPair(impTabL_DEFAULT, + impTabR_INVERSE_LIKE_DIRECT, impAct0, impAct1); + + private static final byte impTabL_INVERSE_LIKE_DIRECT_WITH_MARKS[][] = { + /* + * The case handled in this table is (visually): R EN L + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 0, 0x63, 0, 1, 0, 0, 0, 0 }, /* 1 : L+AN */ { 0, 0x63, 0, 1, 0x12, 0x30, 0, 4 }, + /* 2 : L+AN+ON */ { 0x20, 0x63, 0x20, 1, 2, 0x30, 0x20, 3 }, + /* 3 : R */ { 0, 0x63, 0x55, 0x56, 0x14, 0x30, 0, 3 }, + /* 4 : R+ON */ { 0x30, 0x43, 0x55, 0x56, 4, 0x30, 0x30, 3 }, + /* 5 : R+EN */ { 0x30, 0x43, 5, 0x56, 0x14, 0x30, 0x30, 4 }, + /* 6 : R+AN */ { 0x30, 0x43, 0x55, 6, 0x14, 0x30, 0x30, 4 } }; + private static final byte impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS[][] = { + /* + * The cases handled in this table are (visually): R EN L R L AN L + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 0x13, 0, 1, 1, 0, 0, 0, 0 }, /* 1 : R+EN/AN */ { 0x23, 0, 1, 1, 2, 0x40, 0, 1 }, + /* 2 : R+EN/AN+ON */ { 0x23, 0, 1, 1, 2, 0x40, 0, 0 }, /* 3 : L */ { 3, 0, 3, 0x36, 0x14, 0x40, 0, 1 }, + /* 4 : L+ON */ { 0x53, 0x40, 5, 0x36, 4, 0x40, 0x40, 0 }, + /* 5 : L+ON+EN */ { 0x53, 0x40, 5, 0x36, 4, 0x40, 0x40, 1 }, + /* 6 : L+AN */ { 0x53, 0x40, 6, 6, 4, 0x40, 0x40, 3 } }; + private static final short[] impAct2 = { 0, 1, 2, 5, 6, 7, 8 }; + private static final short[] impAct3 = { 0, 1, 9, 10, 11, 12 }; + private static final ImpTabPair impTab_INVERSE_LIKE_DIRECT_WITH_MARKS = new ImpTabPair( + impTabL_INVERSE_LIKE_DIRECT_WITH_MARKS, impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS, impAct2, impAct3); + + private static final ImpTabPair impTab_INVERSE_FOR_NUMBERS_SPECIAL = new ImpTabPair(impTabL_NUMBERS_SPECIAL, + impTabR_INVERSE_LIKE_DIRECT, impAct0, impAct1); + + private static final byte impTabL_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS[][] = { + /* + * The case handled in this table is (visually): R EN L + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 0, 0x62, 1, 1, 0, 0, 0, 0 }, /* 1 : L+EN/AN */ { 0, 0x62, 1, 1, 0, 0x30, 0, 4 }, + /* 2 : R */ { 0, 0x62, 0x54, 0x54, 0x13, 0x30, 0, 3 }, + /* 3 : R+ON */ { 0x30, 0x42, 0x54, 0x54, 3, 0x30, 0x30, 3 }, + /* 4 : R+EN/AN */ { 0x30, 0x42, 4, 4, 0x13, 0x30, 0x30, 4 } }; + private static final ImpTabPair impTab_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS = new ImpTabPair( + impTabL_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS, impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS, impAct2, impAct3); + + private static class LevState { + byte[][] impTab; /* level table pointer */ + short[] impAct; /* action map array */ + int startON; /* start of ON sequence */ + int startL2EN; /* start of level 2 sequence */ + int lastStrongRTL; /* index of last found R or AL */ + int runStart; /* start position of the run */ + short state; /* current state */ + byte runLevel; /* run level before implicit solving */ + } + + /*------------------------------------------------------------------------*/ + + static final int FIRSTALLOC = 10; + + /* + * param pos: position where to insert param flag: one of LRM_BEFORE, LRM_AFTER, + * RLM_BEFORE, RLM_AFTER + */ + private void addPoint(int pos, int flag) { + Point point = new Point(); + + int len = insertPoints.points.length; + if (len == 0) { + insertPoints.points = new Point[FIRSTALLOC]; + len = FIRSTALLOC; + } + if (insertPoints.size >= len) { /* no room for new point */ + Point[] savePoints = insertPoints.points; + insertPoints.points = new Point[len * 2]; + System.arraycopy(savePoints, 0, insertPoints.points, 0, len); + } + point.pos = pos; + point.flag = flag; + insertPoints.points[insertPoints.size] = point; + insertPoints.size++; + } + + private void setLevelsOutsideIsolates(int start, int limit, byte level) { + byte dirProp; + int isolateCount = 0, k; + for (k = start; k < limit; k++) { + dirProp = dirProps[k]; + if (dirProp == PDI) + isolateCount--; + if (isolateCount == 0) { + levels[k] = level; + } + if (dirProp == LRI || dirProp == RLI) + isolateCount++; + } + } + + /* perform rules (Wn), (Nn), and (In) on a run of the text ------------------ */ + + /* + * This implementation of the (Wn) rules applies all rules in one pass. In order + * to do so, it needs a look-ahead of typically 1 character (except for W5: + * sequences of ET) and keeps track of changes in a rule Wp that affect a later + * Wq (p= 0) { + addPoint(levState.startL2EN, LRM_BEFORE); + } + levState.startL2EN = -1; /* not within previous if since could also be -2 */ + /* check if we had any relevant EN/AN after R/AL */ + if ((insertPoints.points.length == 0) || (insertPoints.size <= insertPoints.confirmed)) { + /* nothing, just clean up */ + levState.lastStrongRTL = -1; + /* check if we have a pending conditional segment */ + level = impTab[oldStateSeq][IMPTABLEVELS_RES]; + if ((level & 1) != 0 && levState.startON > 0) { /* after ON */ + start = levState.startON; /* reset to basic run level */ + } + if (_prop == _S) { /* add LRM before S */ + addPoint(start0, LRM_BEFORE); + insertPoints.confirmed = insertPoints.size; + } + break; + } + /* reset previous RTL cont to level for LTR text */ + for (k = levState.lastStrongRTL + 1; k < start0; k++) { + /* reset odd level, leave runLevel+2 as is */ + levels[k] = (byte) ((levels[k] - 2) & ~1); + } + /* mark insert points as confirmed */ + insertPoints.confirmed = insertPoints.size; + levState.lastStrongRTL = -1; + if (_prop == _S) { /* add LRM before S */ + addPoint(start0, LRM_BEFORE); + insertPoints.confirmed = insertPoints.size; + } + break; + + case 6: /* R/AL after possible relevant EN/AN */ + /* just clean up */ + if (insertPoints.points.length > 0) + /* remove all non confirmed insert points */ + insertPoints.size = insertPoints.confirmed; + levState.startON = -1; + levState.startL2EN = -1; + levState.lastStrongRTL = limit - 1; + break; + + case 7: /* EN/AN after R/AL + possible cont */ + /* check for real AN */ + + if ((_prop == _AN) && (dirProps[start0] == AN) + && (reorderingMode != REORDER_INVERSE_FOR_NUMBERS_SPECIAL)) { + /* real AN */ + if (levState.startL2EN == -1) { /* if no relevant EN already found */ + /* just note the rightmost digit as a strong RTL */ + levState.lastStrongRTL = limit - 1; + break; + } + if (levState.startL2EN >= 0) { /* after EN, no AN */ + addPoint(levState.startL2EN, LRM_BEFORE); + levState.startL2EN = -2; + } + /* note AN */ + addPoint(start0, LRM_BEFORE); + break; + } + /* if first EN/AN after R/AL */ + if (levState.startL2EN == -1) { + levState.startL2EN = start0; + } + break; + + case 8: /* note location of latest R/AL */ + levState.lastStrongRTL = limit - 1; + levState.startON = -1; + break; + + case 9: /* L after R+ON/EN/AN */ + /* include possible adjacent number on the left */ + for (k = start0 - 1; k >= 0 && ((levels[k] & 1) == 0); k--) { + } + if (k >= 0) { + addPoint(k, RLM_BEFORE); /* add RLM before */ + insertPoints.confirmed = insertPoints.size; /* confirm it */ + } + levState.startON = start0; + break; + + case 10: /* AN after L */ + /* AN numbers between L text on both sides may be trouble. */ + /* tentatively bracket with LRMs; will be confirmed if followed by L */ + addPoint(start0, LRM_BEFORE); /* add LRM before */ + addPoint(start0, LRM_AFTER); /* add LRM after */ + break; + + case 11: /* R after L+ON/EN/AN */ + /* false alert, infirm LRMs around previous AN */ + insertPoints.size = insertPoints.confirmed; + if (_prop == _S) { /* add RLM before S */ + addPoint(start0, RLM_BEFORE); + insertPoints.confirmed = insertPoints.size; + } + break; + + case 12: /* L after L+ON/AN */ + level = (byte) (levState.runLevel + addLevel); + for (k = levState.startON; k < start0; k++) { + if (levels[k] < level) { + levels[k] = level; + } + } + insertPoints.confirmed = insertPoints.size; /* confirm inserts */ + levState.startON = start0; + break; + + case 13: /* L after L+ON+EN/AN/ON */ + level = levState.runLevel; + for (k = start0 - 1; k >= levState.startON; k--) { + if (levels[k] == level + 3) { + while (levels[k] == level + 3) { + levels[k--] -= 2; + } + while (levels[k] == level) { + k--; + } + } + if (levels[k] == level + 2) { + levels[k] = level; + continue; + } + levels[k] = (byte) (level + 1); + } + break; + + case 14: /* R after L+ON+EN/AN/ON */ + level = (byte) (levState.runLevel + 1); + for (k = start0 - 1; k >= levState.startON; k--) { + if (levels[k] > level) { + levels[k] -= 2; + } + } + break; + + default: /* we should never get here */ + throw new IllegalStateException("Internal ICU error in processPropertySeq"); + } + } + if ((addLevel) != 0 || (start < start0)) { + level = (byte) (levState.runLevel + addLevel); + if (start >= levState.runStart) { + for (k = start; k < limit; k++) { + levels[k] = level; + } + } else { + setLevelsOutsideIsolates(start, limit, level); + } + } + } + + private void resolveImplicitLevels(int start, int limit, short sor, short eor) { + byte dirProp; + LevState levState = new LevState(); + int i, start1, start2; + short oldStateImp, stateImp, actionImp; + short gprop, resProp, cell; + boolean inverseRTL; + short nextStrongProp = R; + int nextStrongPos = -1; + + /* check for RTL inverse Bidi mode */ + /* + * FOOD FOR THOUGHT: in case of RTL inverse Bidi, it would make sense to loop on + * the text characters from end to start. This would need a different properties + * state table (at least different actions) and different levels state tables + * (maybe very similar to the LTR corresponding ones. + */ + inverseRTL = ((start < lastArabicPos) && ((GetParaLevelAt(start) & 1) > 0) + && (reorderingMode == REORDER_INVERSE_LIKE_DIRECT + || reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL)); + /* initialize for property and levels state table */ + levState.startL2EN = -1; /* used for INVERSE_LIKE_DIRECT_WITH_MARKS */ + levState.lastStrongRTL = -1; /* used for INVERSE_LIKE_DIRECT_WITH_MARKS */ + levState.runStart = start; + levState.runLevel = levels[start]; + levState.impTab = impTabPair.imptab[levState.runLevel & 1]; + levState.impAct = impTabPair.impact[levState.runLevel & 1]; + + /* + * The isolates[] entries contain enough information to resume the bidi + * algorithm in the same state as it was when it was interrupted by an isolate + * sequence. + */ + if (dirProps[start] == PDI) { + levState.startON = isolates[isolateCount].startON; + start1 = isolates[isolateCount].start1; + stateImp = isolates[isolateCount].stateImp; + levState.state = isolates[isolateCount].state; + isolateCount--; + } else { + levState.startON = -1; + start1 = start; + if (dirProps[start] == NSM) + stateImp = (short) (1 + sor); + else + stateImp = 0; + levState.state = 0; + processPropertySeq(levState, sor, start, start); + } + start2 = start; /* to make the Java compiler happy */ + + for (i = start; i <= limit; i++) { + if (i >= limit) { + int k; + for (k = limit - 1; k > start && (DirPropFlag(dirProps[k]) & MASK_BN_EXPLICIT) != 0; k--) + ; + dirProp = dirProps[k]; + if (dirProp == LRI || dirProp == RLI) + break; /* no forced closing for sequence ending with LRI/RLI */ + gprop = eor; + } else { + byte prop, prop1; + prop = dirProps[i]; + if (prop == B) + isolateCount = -1; /* current isolates stack entry == none */ + if (inverseRTL) { + if (prop == AL) { + /* AL before EN does not make it AN */ + prop = R; + } else if (prop == EN) { + if (nextStrongPos <= i) { + /* look for next strong char (L/R/AL) */ + int j; + nextStrongProp = R; /* set default */ + nextStrongPos = limit; + for (j = i + 1; j < limit; j++) { + prop1 = dirProps[j]; + if (prop1 == L || prop1 == R || prop1 == AL) { + nextStrongProp = prop1; + nextStrongPos = j; + break; + } + } + } + if (nextStrongProp == AL) { + prop = AN; + } + } + } + gprop = groupProp[prop]; + } + oldStateImp = stateImp; + cell = impTabProps[oldStateImp][gprop]; + stateImp = GetStateProps(cell); /* isolate the new state */ + actionImp = GetActionProps(cell); /* isolate the action */ + if ((i == limit) && (actionImp == 0)) { + /* there is an unprocessed sequence if its property == eor */ + actionImp = 1; /* process the last sequence */ + } + if (actionImp != 0) { + resProp = impTabProps[oldStateImp][IMPTABPROPS_RES]; + switch (actionImp) { + case 1: /* process current seq1, init new seq1 */ + processPropertySeq(levState, resProp, start1, i); + start1 = i; + break; + case 2: /* init new seq2 */ + start2 = i; + break; + case 3: /* process seq1, process seq2, init new seq1 */ + processPropertySeq(levState, resProp, start1, start2); + processPropertySeq(levState, _ON, start2, i); + start1 = i; + break; + case 4: /* process seq1, set seq1=seq2, init new seq2 */ + processPropertySeq(levState, resProp, start1, start2); + start1 = start2; + start2 = i; + break; + default: /* we should never get here */ + throw new IllegalStateException("Internal ICU error in resolveImplicitLevels"); + } + } + } + + /* look for the last char not a BN or LRE/RLE/LRO/RLO/PDF */ + for (i = limit - 1; i > start && (DirPropFlag(dirProps[i]) & MASK_BN_EXPLICIT) != 0; i--) + ; + dirProp = dirProps[i]; + if ((dirProp == LRI || dirProp == RLI) && limit < length) { + isolateCount++; + if (isolates[isolateCount] == null) + isolates[isolateCount] = new Isolate(); + isolates[isolateCount].stateImp = stateImp; + isolates[isolateCount].state = levState.state; + isolates[isolateCount].start1 = start1; + isolates[isolateCount].startON = levState.startON; + } else + processPropertySeq(levState, eor, limit, limit); + } + + /* perform (L1) and (X9) ---------------------------------------------------- */ + + /* + * Reset the embedding levels for some non-graphic characters (L1). This method + * also sets appropriate levels for BN, and explicit embedding types that are + * supposed to have been removed from the paragraph in (X9). + */ + private void adjustWSLevels() { + int i; + + if ((flags & MASK_WS) != 0) { + int flag; + i = trailingWSStart; + while (i > 0) { + /* reset a sequence of WS/BN before eop and B/S to the paragraph paraLevel */ + while (i > 0 && ((flag = DirPropFlag(dirProps[--i])) & MASK_WS) != 0) { + if (orderParagraphsLTR && (flag & DirPropFlag(B)) != 0) { + levels[i] = 0; + } else { + levels[i] = GetParaLevelAt(i); + } + } + + /* + * reset BN to the next character's paraLevel until B/S, which restarts above + * loop + */ + /* here, i+1 is guaranteed to be 0) { + flag = DirPropFlag(dirProps[--i]); + if ((flag & MASK_BN_EXPLICIT) != 0) { + levels[i] = levels[i + 1]; + } else if (orderParagraphsLTR && (flag & DirPropFlag(B)) != 0) { + levels[i] = 0; + break; + } else if ((flag & MASK_B_S) != 0) { + levels[i] = GetParaLevelAt(i); + break; + } + } + } + } + } + + private void setParaSuccess() { + paraBidi = this; /* mark successful setPara */ + } + + private int Bidi_Min(int x, int y) { + return x < y ? x : y; + } + + private int Bidi_Abs(int x) { + return x >= 0 ? x : -x; + } + + void setParaRunsOnly(char[] parmText, byte parmParaLevel) { + int[] visualMap; + String visualText; + int saveLength, saveTrailingWSStart; + byte[] saveLevels; + byte saveDirection; + int i, j, visualStart, logicalStart, oldRunCount, runLength, addedRuns, insertRemove, start, limit, step, + indexOddBit, logicalPos, index, index1; + int saveOptions; + + reorderingMode = REORDER_DEFAULT; + int parmLength = parmText.length; + if (parmLength == 0) { + setPara(parmText, parmParaLevel, null); + reorderingMode = REORDER_RUNS_ONLY; + return; + } + /* obtain memory for mapping table and visual text */ + saveOptions = reorderingOptions; + if ((saveOptions & OPTION_INSERT_MARKS) > 0) { + reorderingOptions &= ~OPTION_INSERT_MARKS; + reorderingOptions |= OPTION_REMOVE_CONTROLS; + } + parmParaLevel &= 1; /* accept only 0 or 1 */ + setPara(parmText, parmParaLevel, null); + /* + * we cannot access directly levels since it is not yet set if direction is not + * MIXED + */ + saveLevels = new byte[this.length]; + System.arraycopy(getLevels(), 0, saveLevels, 0, this.length); + saveTrailingWSStart = trailingWSStart; + + /* + * FOOD FOR THOUGHT: instead of writing the visual text, we could use the visual + * map and the dirProps array to drive the second call to setPara (but must make + * provision for possible removal of Bidi controls. Alternatively, only use the + * dirProps array via customized classifier callback. + */ + visualText = writeReordered(DO_MIRRORING); + visualMap = getVisualMap(); + this.reorderingOptions = saveOptions; + saveLength = this.length; + saveDirection = this.direction; + + this.reorderingMode = REORDER_INVERSE_LIKE_DIRECT; + parmParaLevel ^= 1; + setPara(visualText, parmParaLevel, null); + BidiLine.getRuns(this); + /* check if some runs must be split, count how many splits */ + addedRuns = 0; + oldRunCount = this.runCount; + visualStart = 0; + for (i = 0; i < oldRunCount; i++, visualStart += runLength) { + runLength = runs[i].limit - visualStart; + if (runLength < 2) { + continue; + } + logicalStart = runs[i].start; + for (j = logicalStart + 1; j < logicalStart + runLength; j++) { + index = visualMap[j]; + index1 = visualMap[j - 1]; + if ((Bidi_Abs(index - index1) != 1) || (saveLevels[index] != saveLevels[index1])) { + addedRuns++; + } + } + } + if (addedRuns > 0) { + getRunsMemory(oldRunCount + addedRuns); + if (runCount == 1) { + /* because we switch from UBiDi.simpleRuns to UBiDi.runs */ + runsMemory[0] = runs[0]; + } else { + System.arraycopy(runs, 0, runsMemory, 0, runCount); + } + runs = runsMemory; + runCount += addedRuns; + for (i = oldRunCount; i < runCount; i++) { + if (runs[i] == null) { + runs[i] = new BidiRun(0, 0, (byte) 0); + } + } + } + /* split runs which are not consecutive in source text */ + int newI; + for (i = oldRunCount - 1; i >= 0; i--) { + newI = i + addedRuns; + runLength = i == 0 ? runs[0].limit : runs[i].limit - runs[i - 1].limit; + logicalStart = runs[i].start; + indexOddBit = runs[i].level & 1; + if (runLength < 2) { + if (addedRuns > 0) { + runs[newI].copyFrom(runs[i]); + } + logicalPos = visualMap[logicalStart]; + runs[newI].start = logicalPos; + runs[newI].level = (byte) (saveLevels[logicalPos] ^ indexOddBit); + continue; + } + if (indexOddBit > 0) { + start = logicalStart; + limit = logicalStart + runLength - 1; + step = 1; + } else { + start = logicalStart + runLength - 1; + limit = logicalStart; + step = -1; + } + for (j = start; j != limit; j += step) { + index = visualMap[j]; + index1 = visualMap[j + step]; + if ((Bidi_Abs(index - index1) != 1) || (saveLevels[index] != saveLevels[index1])) { + logicalPos = Bidi_Min(visualMap[start], index); + runs[newI].start = logicalPos; + runs[newI].level = (byte) (saveLevels[logicalPos] ^ indexOddBit); + runs[newI].limit = runs[i].limit; + runs[i].limit -= Bidi_Abs(j - start) + 1; + insertRemove = runs[i].insertRemove & (LRM_AFTER | RLM_AFTER); + runs[newI].insertRemove = insertRemove; + runs[i].insertRemove &= ~insertRemove; + start = j + step; + addedRuns--; + newI--; + } + } + if (addedRuns > 0) { + runs[newI].copyFrom(runs[i]); + } + logicalPos = Bidi_Min(visualMap[start], visualMap[limit]); + runs[newI].start = logicalPos; + runs[newI].level = (byte) (saveLevels[logicalPos] ^ indexOddBit); + } + + cleanup1: + /* restore initial paraLevel */ + this.paraLevel ^= 1; + cleanup2: + /* restore real text */ + this.text = parmText; + this.length = saveLength; + this.originalLength = parmLength; + this.direction = saveDirection; + this.levels = saveLevels; + this.trailingWSStart = saveTrailingWSStart; + if (runCount > 1) { + this.direction = MIXED; + } + cleanup3: this.reorderingMode = REORDER_RUNS_ONLY; + } + + /** + * Perform the Unicode Bidi algorithm. It is defined in the + * Unicode Standard Annex #9: + * Unicode Bidirectional Algorithm, version 13, also described in The + * Unicode Standard, Version 4.0 . + *

+ * + * This method takes a piece of plain text containing one or more paragraphs, + * with or without externally specified embedding levels from styled text + * and computes the left-right-directionality of each character. + *

+ * + * If the entire text is all of the same directionality, then the method may not + * perform all the steps described by the algorithm, i.e., some levels may not + * be the same as if all steps were performed. This is not relevant for + * unidirectional text.
+ * For example, in pure LTR text with numbers the numbers would get a resolved + * level of 2 higher than the surrounding text according to the algorithm. This + * implementation may set all resolved levels to the same value in such a case. + *

+ * + * The text can be composed of multiple paragraphs. Occurrence of a block + * separator in the text terminates a paragraph, and whatever comes next starts + * a new paragraph. The exception to this rule is when a Carriage Return (CR) is + * followed by a Line Feed (LF). Both CR and LF are block separators, but in + * that case, the pair of characters is considered as terminating the preceding + * paragraph, and a new paragraph will be started by a character coming after + * the LF. + * + * Although the text is passed here as a String, it is stored + * internally as an array of characters. Therefore the documentation will refer + * to indexes of the characters in the text. + * + * @param text contains the text that the Bidi algorithm will be + * performed on. This text can be retrieved with + * getText() or + * getTextAsString.
+ * + * @param paraLevel specifies the default level for the text; it is + * typically 0 (LTR) or 1 (RTL). If the method shall + * determine the paragraph level from the text, then + * paraLevel can be set to either + * LEVEL_DEFAULT_LTR or + * LEVEL_DEFAULT_RTL; if the text contains + * multiple paragraphs, the paragraph level shall be + * determined separately for each paragraph; if a + * paragraph does not include any strongly typed + * character, then the desired default is used (0 for LTR + * or 1 for RTL). Any other value between 0 and + * MAX_EXPLICIT_LEVEL is also valid, with + * odd levels indicating RTL. + * + * @param embeddingLevels (in) may be used to preset the embedding and override + * levels, ignoring characters like LRE and PDF in the + * text. A level overrides the directional property of + * its corresponding (same index) character if the level + * has the LEVEL_OVERRIDE bit set.
+ *
+ * Except for that bit, it must be + * paraLevel<=embeddingLevels[]<=MAX_EXPLICIT_LEVEL, + * with one exception: a level of zero may be specified + * for a paragraph separator even if + * paraLevel>0 when multiple paragraphs + * are submitted in the same call to + * setPara().
+ *
+ * Caution: A reference to this array, + * not a copy of the levels, will be stored in the + * Bidi object; the + * embeddingLevels should not be modified to + * avoid unexpected results on subsequent Bidi + * operations. However, the setPara() and + * setLine() methods may modify some or all + * of the levels.
+ *
+ * Note: the + * embeddingLevels array must have one entry + * for each character in text. + * + * @throws IllegalArgumentException if the values in embeddingLevels are not + * within the allowed range + * + * @see #LEVEL_DEFAULT_LTR + * @see #LEVEL_DEFAULT_RTL + * @see #LEVEL_OVERRIDE + * @see #MAX_EXPLICIT_LEVEL + * @stable ICU 3.8 + */ + void setPara(String text, byte paraLevel, byte[] embeddingLevels) { + if (text == null) { + setPara(new char[0], paraLevel, embeddingLevels); + } else { + setPara(text.toCharArray(), paraLevel, embeddingLevels); + } + } + + /** + * Perform the Unicode Bidi algorithm. It is defined in the + * Unicode Standard Annex #9: + * Unicode Bidirectional Algorithm, version 13, also described in The + * Unicode Standard, Version 4.0 . + *

+ * + * This method takes a piece of plain text containing one or more paragraphs, + * with or without externally specified embedding levels from styled text + * and computes the left-right-directionality of each character. + *

+ * + * If the entire text is all of the same directionality, then the method may not + * perform all the steps described by the algorithm, i.e., some levels may not + * be the same as if all steps were performed. This is not relevant for + * unidirectional text.
+ * For example, in pure LTR text with numbers the numbers would get a resolved + * level of 2 higher than the surrounding text according to the algorithm. This + * implementation may set all resolved levels to the same value in such a case. + * + * The text can be composed of multiple paragraphs. Occurrence of a block + * separator in the text terminates a paragraph, and whatever comes next starts + * a new paragraph. The exception to this rule is when a Carriage Return (CR) is + * followed by a Line Feed (LF). Both CR and LF are block separators, but in + * that case, the pair of characters is considered as terminating the preceding + * paragraph, and a new paragraph will be started by a character coming after + * the LF. + * + * The text is stored internally as an array of characters. Therefore the + * documentation will refer to indexes of the characters in the text. + * + * @param chars contains the text that the Bidi algorithm will be + * performed on. This text can be retrieved with + * getText() or + * getTextAsString.
+ * + * @param paraLevel specifies the default level for the text; it is + * typically 0 (LTR) or 1 (RTL). If the method shall + * determine the paragraph level from the text, then + * paraLevel can be set to either + * LEVEL_DEFAULT_LTR or + * LEVEL_DEFAULT_RTL; if the text contains + * multiple paragraphs, the paragraph level shall be + * determined separately for each paragraph; if a + * paragraph does not include any strongly typed + * character, then the desired default is used (0 for LTR + * or 1 for RTL). Any other value between 0 and + * MAX_EXPLICIT_LEVEL is also valid, with + * odd levels indicating RTL. + * + * @param embeddingLevels (in) may be used to preset the embedding and override + * levels, ignoring characters like LRE and PDF in the + * text. A level overrides the directional property of + * its corresponding (same index) character if the level + * has the LEVEL_OVERRIDE bit set.
+ *
+ * Except for that bit, it must be + * paraLevel<=embeddingLevels[]<=MAX_EXPLICIT_LEVEL, + * with one exception: a level of zero may be specified + * for a paragraph separator even if + * paraLevel>0 when multiple paragraphs + * are submitted in the same call to + * setPara().
+ *
+ * Caution: A reference to this array, + * not a copy of the levels, will be stored in the + * Bidi object; the + * embeddingLevels should not be modified to + * avoid unexpected results on subsequent Bidi + * operations. However, the setPara() and + * setLine() methods may modify some or all + * of the levels.
+ *
+ * Note: the + * embeddingLevels array must have one entry + * for each character in text. + * + * @throws IllegalArgumentException if the values in embeddingLevels are not + * within the allowed range + * + * @see #LEVEL_DEFAULT_LTR + * @see #LEVEL_DEFAULT_RTL + * @see #LEVEL_OVERRIDE + * @see #MAX_EXPLICIT_LEVEL + * @stable ICU 3.8 + */ + void setPara(char[] chars, byte paraLevel, byte[] embeddingLevels) { + /* check the argument values */ + if (paraLevel < LEVEL_DEFAULT_LTR) { + verifyRange(paraLevel, 0, MAX_EXPLICIT_LEVEL + 1); + } + if (chars == null) { + chars = new char[0]; + } + + /* special treatment for RUNS_ONLY mode */ + if (reorderingMode == REORDER_RUNS_ONLY) { + setParaRunsOnly(chars, paraLevel); + return; + } + + /* initialize the Bidi object */ + this.paraBidi = null; /* mark unfinished setPara */ + this.text = chars; + this.length = this.originalLength = this.resultLength = text.length; + this.paraLevel = paraLevel; + this.direction = (byte) (paraLevel & 1); + this.paraCount = 1; + + /* + * Allocate zero-length arrays instead of setting to null here; then checks for + * null in various places can be eliminated. + */ + dirProps = new byte[0]; + levels = new byte[0]; + runs = new BidiRun[0]; + isGoodLogicalToVisualRunsMap = false; + insertPoints.size = 0; /* clean up from last call */ + insertPoints.confirmed = 0; /* clean up from last call */ + + /* + * Save the original paraLevel if contextual; otherwise, set to 0. + */ + defaultParaLevel = IsDefaultLevel(paraLevel) ? paraLevel : 0; + + if (length == 0) { + /* + * For an empty paragraph, create a Bidi object with the paraLevel and the flags + * and the direction set but without allocating zero-length arrays. There is + * nothing more to do. + */ + if (IsDefaultLevel(paraLevel)) { + this.paraLevel &= 1; + defaultParaLevel = 0; + } + flags = DirPropFlagLR(paraLevel); + runCount = 0; + paraCount = 0; + setParaSuccess(); + return; + } + + runCount = -1; + + /* + * Get the directional properties, the flags bit-set, and determine the + * paragraph level if necessary. + */ + getDirPropsMemory(length); + dirProps = dirPropsMemory; + getDirProps(); + /* the processed length may have changed if OPTION_STREAMING is set */ + trailingWSStart = length; /* the levels[] will reflect the WS run */ + + /* are explicit levels specified? */ + if (embeddingLevels == null) { + /* no: determine explicit levels according to the (Xn) rules */ + getLevelsMemory(length); + levels = levelsMemory; + direction = resolveExplicitLevels(); + } else { + /* + * set BN for all explicit codes, check that all levels are 0 or + * paraLevel..MAX_EXPLICIT_LEVEL + */ + levels = embeddingLevels; + direction = checkExplicitLevels(); + } + + /* allocate isolate memory */ + if (isolateCount > 0) { + if (isolates == null || isolates.length < isolateCount) + isolates = new Isolate[isolateCount + 3]; /* keep some reserve */ + } + isolateCount = -1; /* current isolates stack entry == none */ + + /* + * The steps after (X9) in the Bidi algorithm are performed only if the + * paragraph text has mixed directionality! + */ + switch (direction) { + case LTR: + /* all levels are implicitly at paraLevel (important for getLevels()) */ + trailingWSStart = 0; + break; + case RTL: + /* all levels are implicitly at paraLevel (important for getLevels()) */ + trailingWSStart = 0; + break; + default: + /* + * Choose the right implicit state table + */ + switch (reorderingMode) { + case REORDER_DEFAULT: + this.impTabPair = impTab_DEFAULT; + break; + case REORDER_NUMBERS_SPECIAL: + this.impTabPair = impTab_NUMBERS_SPECIAL; + break; + case REORDER_GROUP_NUMBERS_WITH_R: + this.impTabPair = impTab_GROUP_NUMBERS_WITH_R; + break; + case REORDER_RUNS_ONLY: + /* we should never get here */ + throw new InternalError("Internal ICU error in setPara"); + /* break; */ + case REORDER_INVERSE_NUMBERS_AS_L: + this.impTabPair = impTab_INVERSE_NUMBERS_AS_L; + break; + case REORDER_INVERSE_LIKE_DIRECT: + if ((reorderingOptions & OPTION_INSERT_MARKS) != 0) { + this.impTabPair = impTab_INVERSE_LIKE_DIRECT_WITH_MARKS; + } else { + this.impTabPair = impTab_INVERSE_LIKE_DIRECT; + } + break; + case REORDER_INVERSE_FOR_NUMBERS_SPECIAL: + if ((reorderingOptions & OPTION_INSERT_MARKS) != 0) { + this.impTabPair = impTab_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS; + } else { + this.impTabPair = impTab_INVERSE_FOR_NUMBERS_SPECIAL; + } + break; + } + /* + * If there are no external levels specified and there are no significant + * explicit level codes in the text, then we can treat the entire paragraph as + * one run. Otherwise, we need to perform the following rules on runs of the + * text with the same embedding levels. (X10) "Significant" explicit level codes + * are ones that actually affect non-BN characters. Examples for "insignificant" + * ones are empty embeddings LRE-PDF, LRE-RLE-PDF-PDF, etc. + */ + if (embeddingLevels == null && paraCount <= 1 && (flags & DirPropFlagMultiRuns) == 0) { + resolveImplicitLevels(0, length, GetLRFromLevel(GetParaLevelAt(0)), + GetLRFromLevel(GetParaLevelAt(length - 1))); + } else { + /* sor, eor: start and end types of same-level-run */ + int start, limit = 0; + byte level, nextLevel; + short sor, eor; + + /* + * determine the first sor and set eor to it because of the loop body (sor=eor + * there) + */ + level = GetParaLevelAt(0); + nextLevel = levels[0]; + if (level < nextLevel) { + eor = GetLRFromLevel(nextLevel); + } else { + eor = GetLRFromLevel(level); + } + + do { + /* determine start and limit of the run (end points just behind the run) */ + + /* the values for this run's start are the same as for the previous run's end */ + start = limit; + level = nextLevel; + if ((start > 0) && (dirProps[start - 1] == B)) { + /* except if this is a new paragraph, then set sor = para level */ + sor = GetLRFromLevel(GetParaLevelAt(start)); + } else { + sor = eor; + } + + /* search for the limit of this run */ + while ((++limit < length) + && ((levels[limit] == level) || ((DirPropFlag(dirProps[limit]) & MASK_BN_EXPLICIT) != 0))) { + } + + /* get the correct level of the next run */ + if (limit < length) { + nextLevel = levels[limit]; + } else { + nextLevel = GetParaLevelAt(length - 1); + } + + /* determine eor from max(level, nextLevel); sor is last run's eor */ + if (NoOverride(level) < NoOverride(nextLevel)) { + eor = GetLRFromLevel(nextLevel); + } else { + eor = GetLRFromLevel(level); + } + + /* + * if the run consists of overridden directional types, then there are no + * implicit types to be resolved + */ + if ((level & LEVEL_OVERRIDE) == 0) { + resolveImplicitLevels(start, limit, sor, eor); + } else { + /* remove the LEVEL_OVERRIDE flags */ + do { + levels[start++] &= ~LEVEL_OVERRIDE; + } while (start < limit); + } + } while (limit < length); + } + + /* reset the embedding levels for some non-graphic characters (L1), (X9) */ + adjustWSLevels(); + + break; + } + + /* + * add RLM for inverse Bidi with contextual orientation resolving to RTL which + * would not round-trip otherwise + */ + if ((defaultParaLevel > 0) && ((reorderingOptions & OPTION_INSERT_MARKS) != 0) + && ((reorderingMode == REORDER_INVERSE_LIKE_DIRECT) + || (reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL))) { + int start, last; + byte level; + byte dirProp; + for (int i = 0; i < paraCount; i++) { + last = paras_limit[i] - 1; + level = paras_level[i]; + if (level == 0) + continue; /* LTR paragraph */ + start = i == 0 ? 0 : paras_limit[i - 1]; + for (int j = last; j >= start; j--) { + dirProp = dirProps[j]; + if (dirProp == L) { + if (j < last) { + while (dirProps[last] == B) { + last--; + } + } + addPoint(last, RLM_BEFORE); + break; + } + if ((DirPropFlag(dirProp) & MASK_R_AL) != 0) { + break; + } + } + } + } + + if ((reorderingOptions & OPTION_REMOVE_CONTROLS) != 0) { + resultLength -= controlCount; + } else { + resultLength += insertPoints.size; + } + setParaSuccess(); + } + + /** + * Perform the Unicode Bidi algorithm on a given paragraph, as defined in the + * Unicode Standard Annex #9: + * Unicode Bidirectional Algorithm, version 13, also described in The + * Unicode Standard, Version 4.0 . + *

+ * + * This method takes a paragraph of text and computes the + * left-right-directionality of each character. The text should not contain any + * Unicode block separators. + *

+ * + * The RUN_DIRECTION attribute in the text, if present, determines the base + * direction (left-to-right or right-to-left). If not present, the base + * direction is computed using the Unicode Bidirectional Algorithm, defaulting + * to left-to-right if there are no strong directional characters in the text. + * This attribute, if present, must be applied to all the text in the paragraph. + *

+ * + * The BIDI_EMBEDDING attribute in the text, if present, represents embedding + * level information. Negative values from -1 to -62 indicate overrides at the + * absolute value of the level. Positive values from 1 to 62 indicate + * embeddings. Where values are zero or not defined, the base embedding level as + * determined by the base direction is assumed. + *

+ * + * The NUMERIC_SHAPING attribute in the text, if present, converts European + * digits to other decimal digits before running the bidi algorithm. This + * attribute, if present, must be applied to all the text in the paragraph. + * + * If the entire text is all of the same directionality, then the method may not + * perform all the steps described by the algorithm, i.e., some levels may not + * be the same as if all steps were performed. This is not relevant for + * unidirectional text.
+ * For example, in pure LTR text with numbers the numbers would get a resolved + * level of 2 higher than the surrounding text according to the algorithm. This + * implementation may set all resolved levels to the same value in such a case. + *

+ * + * @param paragraph a paragraph of text with optional character and paragraph + * attribute information + * @stable ICU 3.8 + */ + public void setPara(AttributedCharacterIterator paragraph) { + byte paraLvl; + char ch = paragraph.first(); + Boolean runDirection = (Boolean) paragraph.getAttribute(TextAttribute.RUN_DIRECTION); + Object shaper = paragraph.getAttribute(TextAttribute.NUMERIC_SHAPING); + + if (runDirection == null) { + paraLvl = LEVEL_DEFAULT_LTR; + } else { + paraLvl = (runDirection.equals(TextAttribute.RUN_DIRECTION_LTR)) ? LTR : RTL; + } + + byte[] lvls = null; + int len = paragraph.getEndIndex() - paragraph.getBeginIndex(); + byte[] embeddingLevels = new byte[len]; + char[] txt = new char[len]; + int i = 0; + while (ch != AttributedCharacterIterator.DONE) { + txt[i] = ch; + Integer embedding = (Integer) paragraph.getAttribute(TextAttribute.BIDI_EMBEDDING); + if (embedding != null) { + byte level = embedding.byteValue(); + if (level == 0) { + /* no-op */ + } else if (level < 0) { + lvls = embeddingLevels; + embeddingLevels[i] = (byte) ((0 - level) | LEVEL_OVERRIDE); + } else { + lvls = embeddingLevels; + embeddingLevels[i] = level; + } + } + ch = paragraph.next(); + ++i; + } + + if (shaper != null) { + ((NumericShaper) shaper).shape(txt, 0, len); + } + setPara(txt, paraLvl, lvls); + } + + /** + * Specify whether block separators must be allocated level zero, so that + * successive paragraphs will progress from left to right. This method must be + * called before setPara(). Paragraph separators (B) may appear in + * the text. Setting them to level zero means that all paragraph separators + * (including one possibly appearing in the last text position) are kept in the + * reordered text after the text that they follow in the source text. When this + * feature is not enabled, a paragraph separator at the last position of the + * text before reordering will go to the first position of the reordered text + * when the paragraph level is odd. + * + * @param ordarParaLTR specifies whether paragraph separators (B) must receive + * level 0, so that successive paragraphs progress from left + * to right. + * + * @see #setPara + * @stable ICU 3.8 + */ + public void orderParagraphsLTR(boolean ordarParaLTR) { + orderParagraphsLTR = ordarParaLTR; + } + + /** + * Get the directionality of the text. + * + * @return a value of LTR, RTL or MIXED + * that indicates if the entire text represented by this object is + * unidirectional, and which direction, or if it is mixed-directional. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * + * @see #LTR + * @see #RTL + * @see #MIXED + * @stable ICU 3.8 + */ + public byte getDirection() { + verifyValidParaOrLine(); + return direction; + } + + /** + * Get the length of the text. + * + * @return The length of the text that the Bidi object was created + * for. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * @stable ICU 3.8 + */ + public int getLength() { + verifyValidParaOrLine(); + return originalLength; + } + + /* paragraphs API methods ------------------------------------------------- */ + + /** + * Get the paragraph level of the text. + * + * @return The paragraph level. If there are multiple paragraphs, their level + * may vary if the required paraLevel is LEVEL_DEFAULT_LTR or + * LEVEL_DEFAULT_RTL. In that case, the level of the first paragraph is + * returned. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * + * @see #LEVEL_DEFAULT_LTR + * @see #LEVEL_DEFAULT_RTL + * @see #getParagraph + * @see #getParagraphByIndex + * @stable ICU 3.8 + */ + public byte getParaLevel() { + verifyValidParaOrLine(); + return paraLevel; + } + + /** + * Retrieves the Bidi class for a given code point. + *

+ * If a BidiClassifier is defined and returns a value other than + * CLASS_DEFAULT, that value is used; otherwise the default class + * determination mechanism is invoked. + *

+ * + * @param c The code point to get a Bidi class for. + * + * @return The Bidi class for the character c that is in effect for + * this Bidi instance. + * + * @stable ICU 3.8 + */ + public int getCustomizedClass(int c) { + int dir; + + dir = bdp.getClass(c); + if (dir >= CHAR_DIRECTION_COUNT) + dir = ON; + return dir; + } + + /** + * setLine() returns a Bidi object to contain the + * reordering information, especially the resolved levels, for all the + * characters in a line of text. This line of text is specified by referring to + * a Bidi object representing this information for a piece of text + * containing one or more paragraphs, and by specifying a range of indexes in + * this text. + *

+ * In the new line object, the indexes will range from 0 to + * limit-start-1. + *

+ * + * This is used after calling setPara() for a piece of text, and + * after line-breaking on that text. It is not necessary if each paragraph is + * treated as a single line. + *

+ * + * After line-breaking, rules (L1) and (L2) for the treatment of trailing WS and + * for reordering are performed on a Bidi object that represents a + * line. + *

+ * + * Important: the line Bidi object may reference + * data within the global text Bidi object. You should not alter + * the content of the global text object until you are finished using the line + * object. + * + * @param start is the line's first index into the text. + * + * @param limit is just behind the line's last index into the text (its last + * index +1). + * + * @return a Bidi object that will now represent a line of the + * text. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara + * @throws IllegalArgumentException if start and limit are not in the range + * 0<=start<limit<=getProcessedLength(), + * or if the specified line crosses a paragraph + * boundary + * + * @see #setPara + * @see #getProcessedLength + * @stable ICU 3.8 + */ + public Bidi setLine(Bidi bidi, BidiBase bidiBase, Bidi newBidi, BidiBase newBidiBase, int start, int limit) { + verifyValidPara(); + verifyRange(start, 0, limit); + verifyRange(limit, 0, length + 1); + + return BidiLine.setLine(this, newBidi, newBidiBase, start, limit); + } + + /** + * Get the level for one character. + * + * @param charIndex the index of a character. + * + * @return The level for the character at charIndex. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * @throws IllegalArgumentException if charIndex is not in the range + * 0<=charIndex<getProcessedLength() + * + * @see #getProcessedLength + * @stable ICU 3.8 + */ + public byte getLevelAt(int charIndex) { + // for backward compatibility + if (charIndex < 0 || charIndex >= length) { + return (byte) getBaseLevel(); + } + + verifyValidParaOrLine(); + verifyRange(charIndex, 0, length); + return BidiLine.getLevelAt(this, charIndex); + } + + /** + * Get an array of levels for each character. + *

+ * + * Note that this method may allocate memory under some circumstances, unlike + * getLevelAt(). + * + * @return The levels array for the text, or null if an error + * occurs. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * @stable ICU 3.8 + */ + byte[] getLevels() { + verifyValidParaOrLine(); + if (length <= 0) { + return new byte[0]; + } + return BidiLine.getLevels(this); + } + + /** + * Get the number of runs. This method may invoke the actual reordering on the + * Bidi object, after setPara() may have resolved only + * the levels of the text. Therefore, countRuns() may have to + * allocate memory, and may throw an exception if it fails to do so. + * + * @return The number of runs. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * @stable ICU 3.8 + */ + public int countRuns() { + verifyValidParaOrLine(); + BidiLine.getRuns(this); + return runCount; + } + + /** + * + * Get a BidiRun object according to its index. BidiRun methods may + * be used to retrieve the run's logical start, length and level, which can be + * even for an LTR run or odd for an RTL run. In an RTL run, the character at + * the logical start is visually on the right of the displayed run. The length + * is the number of characters in the run. + *

+ * countRuns() is normally called before the runs are retrieved. + * + *

+ * Example: + * + *

+	 * Bidi bidi = new Bidi();
+	 * String text = "abc 123 DEFG xyz";
+	 * bidi.setPara(text, Bidi.RTL, null);
+	 * int i, count = bidi.countRuns(), logicalStart, visualIndex = 0, length;
+	 * BidiRun run;
+	 * for (i = 0; i < count; ++i) {
+	 * 	run = bidi.getVisualRun(i);
+	 * 	logicalStart = run.getStart();
+	 * 	length = run.getLength();
+	 * 	if (Bidi.LTR == run.getEmbeddingLevel()) {
+	 * 		do { // LTR
+	 * 			show_char(text.charAt(logicalStart++), visualIndex++);
+	 * 		} while (--length > 0);
+	 * 	} else {
+	 * 		logicalStart += length; // logicalLimit
+	 * 		do { // RTL
+	 * 			show_char(text.charAt(--logicalStart), visualIndex++);
+	 * 		} while (--length > 0);
+	 * 	}
+	 * }
+	 * 
+ *

+ * Note that in right-to-left runs, code like this places second surrogates + * before first ones (which is generally a bad idea) and combining characters + * before base characters. + *

+ * Use of {@link #writeReordered}, optionally with the + * {@link #KEEP_BASE_COMBINING} option, can be considered in order + * to avoid these issues. + * + * @param runIndex is the number of the run in visual order, in the range + * [0..countRuns()-1]. + * + * @return a BidiRun object containing the details of the run. The + * directionality of the run is LTR==0 or + * RTL==1, never MIXED. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * @throws IllegalArgumentException if runIndex is not in the range + * 0<=runIndex<countRuns() + * + * @see #countRuns() + * @see com.ibm.icu.text.BidiRun + * @see com.ibm.icu.text.BidiRun#getStart() + * @see com.ibm.icu.text.BidiRun#getLength() + * @see com.ibm.icu.text.BidiRun#getEmbeddingLevel() + * @stable ICU 3.8 + */ + BidiRun getVisualRun(int runIndex) { + verifyValidParaOrLine(); + BidiLine.getRuns(this); + verifyRange(runIndex, 0, runCount); + return BidiLine.getVisualRun(this, runIndex); + } + + /** + * Get a visual-to-logical index map (array) for the characters in the + * Bidi (paragraph or line) object. + *

+ * Some values in the map may be MAP_NOWHERE if the corresponding + * text characters are Bidi marks inserted in the visual output by the option + * OPTION_INSERT_MARKS. + *

+ * When the visual output is altered by using options of + * writeReordered() such as INSERT_LRM_FOR_NUMERIC, + * KEEP_BASE_COMBINING, OUTPUT_REVERSE, + * REMOVE_BIDI_CONTROLS, the logical positions returned may not be + * correct. It is advised to use, when possible, reordering options such as + * {@link #OPTION_INSERT_MARKS} and {@link #OPTION_REMOVE_CONTROLS}. + * + * @return an array of getResultLength() indexes which will reflect + * the reordering of the characters.
+ *
+ * The index map will result in + * indexMap[visualIndex]==logicalIndex, where + * indexMap represents the returned array. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * + * @see #getLogicalMap + * @see #getLogicalIndex + * @see #getResultLength + * @see #MAP_NOWHERE + * @see #OPTION_INSERT_MARKS + * @see #writeReordered + * @stable ICU 3.8 + */ + private int[] getVisualMap() { + /* countRuns() checks successful call to setPara/setLine */ + countRuns(); + if (resultLength <= 0) { + return new int[0]; + } + return BidiLine.getVisualMap(this); + } + + /** + * This is a convenience method that does not use a Bidi object. It + * is intended to be used for when an application has determined the levels of + * objects (character sequences) and just needs to have them reordered (L2). + * This is equivalent to using getVisualMap() on a + * Bidi object. + * + * @param levels is an array of levels that have been determined by the + * application. + * + * @return an array of levels.length indexes which will reflect the + * reordering of the characters. + *

+ * The index map will result in + * indexMap[visualIndex]==logicalIndex, where + * indexMap represents the returned array. + * + * @stable ICU 3.8 + */ + private static int[] reorderVisual(byte[] levels) { + return BidiLine.reorderVisual(levels); + } + + /** + * Constant indicating that the base direction depends on the first strong + * directional character in the text according to the Unicode Bidirectional + * Algorithm. If no strong directional character is present, the base direction + * is right-to-left. + * + * @stable ICU 3.8 + */ + public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT = LEVEL_DEFAULT_RTL; + + /** + * Create Bidi from the given text, embedding, and direction information. The + * embeddings array may be null. If present, the values represent embedding + * level information. Negative values from -1 to -61 indicate overrides at the + * absolute value of the level. Positive values from 1 to 61 indicate + * embeddings. Where values are zero, the base embedding level as determined by + * the base direction is assumed. + *

+ * + * Note: this constructor calls setPara() internally. + * + * @param text an array containing the paragraph of text to process. + * @param textStart the index into the text array of the start of the + * paragraph. + * @param embeddings an array containing embedding values for each + * character in the paragraph. This can be null, in which + * case it is assumed that there is no external embedding + * information. + * @param embStart the index into the embedding array of the start of the + * paragraph. + * @param paragraphLength the length of the paragraph in the text and embeddings + * arrays. + * @param flags a collection of flags that control the algorithm. The + * algorithm understands the flags + * DIRECTION_LEFT_TO_RIGHT, DIRECTION_RIGHT_TO_LEFT, + * DIRECTION_DEFAULT_LEFT_TO_RIGHT, and + * DIRECTION_DEFAULT_RIGHT_TO_LEFT. Other values are + * reserved. + * + * @throws IllegalArgumentException if the values in embeddings are not within + * the allowed range + * + * @see #DIRECTION_LEFT_TO_RIGHT + * @see #DIRECTION_RIGHT_TO_LEFT + * @see #DIRECTION_DEFAULT_LEFT_TO_RIGHT + * @see #DIRECTION_DEFAULT_RIGHT_TO_LEFT + * @stable ICU 3.8 + */ + public BidiBase(char[] text, int textStart, byte[] embeddings, int embStart, int paragraphLength, int flags) { + this(0, 0); + byte paraLvl; + switch (flags) { + case Bidi.DIRECTION_LEFT_TO_RIGHT: + default: + paraLvl = LTR; + break; + case Bidi.DIRECTION_RIGHT_TO_LEFT: + paraLvl = RTL; + break; + case Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT: + paraLvl = LEVEL_DEFAULT_LTR; + break; + case Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT: + paraLvl = LEVEL_DEFAULT_RTL; + break; + } + byte[] paraEmbeddings; + if (embeddings == null) { + paraEmbeddings = null; + } else { + paraEmbeddings = new byte[paragraphLength]; + byte lev; + for (int i = 0; i < paragraphLength; i++) { + lev = embeddings[i + embStart]; + if (lev < 0) { + lev = (byte) ((-lev) | LEVEL_OVERRIDE); + } else if (lev == 0) { + lev = paraLvl; + if (paraLvl > MAX_EXPLICIT_LEVEL) { + lev &= 1; + } + } + paraEmbeddings[i] = lev; + } + } + + char[] paraText = new char[paragraphLength]; + System.arraycopy(text, textStart, paraText, 0, paragraphLength); + setPara(paraText, paraLvl, paraEmbeddings); + } + + /** + * Return true if the line is not left-to-right or right-to-left. This means it + * either has mixed runs of left-to-right and right-to-left text, or the base + * direction differs from the direction of the only run of text. + * + * @return true if the line is not left-to-right or right-to-left. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara + * @stable ICU 3.8 + */ + public boolean isMixed() { + return (!isLeftToRight() && !isRightToLeft()); + } + + /** + * Return true if the line is all left-to-right text and the base direction is + * left-to-right. + * + * @return true if the line is all left-to-right text and the base direction is + * left-to-right. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara + * @stable ICU 3.8 + */ + public boolean isLeftToRight() { + return (getDirection() == LTR && (paraLevel & 1) == 0); + } + + /** + * Return true if the line is all right-to-left text, and the base direction is + * right-to-left + * + * @return true if the line is all right-to-left text, and the base direction is + * right-to-left + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara + * @stable ICU 3.8 + */ + public boolean isRightToLeft() { + return (getDirection() == RTL && (paraLevel & 1) == 1); + } + + /** + * Return true if the base direction is left-to-right + * + * @return true if the base direction is left-to-right + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * + * @stable ICU 3.8 + */ + public boolean baseIsLeftToRight() { + return (getParaLevel() == LTR); + } + + /** + * Return the base level (0 if left-to-right, 1 if right-to-left). + * + * @return the base level + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * + * @stable ICU 3.8 + */ + public int getBaseLevel() { + return getParaLevel(); + } + + /** + * Compute the logical to visual run mapping + */ + void getLogicalToVisualRunsMap() { + if (isGoodLogicalToVisualRunsMap) { + return; + } + int count = countRuns(); + if ((logicalToVisualRunsMap == null) || (logicalToVisualRunsMap.length < count)) { + logicalToVisualRunsMap = new int[count]; + } + int i; + long[] keys = new long[count]; + for (i = 0; i < count; i++) { + keys[i] = ((long) (runs[i].start) << 32) + i; + } + Arrays.sort(keys); + for (i = 0; i < count; i++) { + logicalToVisualRunsMap[i] = (int) (keys[i] & 0x00000000FFFFFFFF); + } + isGoodLogicalToVisualRunsMap = true; + } + + /** + * Return the level of the nth logical run in this line. + * + * @param run the index of the run, between 0 and countRuns()-1 + * + * @return the level of the run + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * @throws IllegalArgumentException if run is not in the range + * 0<=run<countRuns() + * @stable ICU 3.8 + */ + public int getRunLevel(int run) { + verifyValidParaOrLine(); + BidiLine.getRuns(this); + + // for backward compatibility + if (run < 0 || run >= runCount) { + return getParaLevel(); + } + + getLogicalToVisualRunsMap(); + return runs[logicalToVisualRunsMap[run]].level; + } + + /** + * Return the index of the character at the start of the nth logical run in this + * line, as an offset from the start of the line. + * + * @param run the index of the run, between 0 and countRuns() + * + * @return the start of the run + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * @throws IllegalArgumentException if run is not in the range + * 0<=run<countRuns() + * @stable ICU 3.8 + */ + public int getRunStart(int run) { + verifyValidParaOrLine(); + BidiLine.getRuns(this); + + // for backward compatibility + if (runCount == 1) { + return 0; + } else if (run == runCount) { + return length; + } + + getLogicalToVisualRunsMap(); + return runs[logicalToVisualRunsMap[run]].start; + } + + /** + * Return the index of the character past the end of the nth logical run in this + * line, as an offset from the start of the line. For example, this will return + * the length of the line for the last run on the line. + * + * @param run the index of the run, between 0 and countRuns() + * + * @return the limit of the run + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * @throws IllegalArgumentException if run is not in the range + * 0<=run<countRuns() + * @stable ICU 3.8 + */ + public int getRunLimit(int run) { + verifyValidParaOrLine(); + BidiLine.getRuns(this); + + // for backward compatibility + if (runCount == 1) { + return length; + } + + getLogicalToVisualRunsMap(); + int idx = logicalToVisualRunsMap[run]; + int len = idx == 0 ? runs[idx].limit : runs[idx].limit - runs[idx - 1].limit; + return runs[idx].start + len; + } + + /** + * Return true if the specified text requires bidi analysis. If this returns + * false, the text will display left-to-right. Clients can then avoid + * constructing a Bidi object. Text in the Arabic Presentation Forms area of + * Unicode is presumed to already be shaped and ordered for display, and so will + * not cause this method to return true. + * + * @param text the text containing the characters to test + * @param start the start of the range of characters to test + * @param limit the limit of the range of characters to test + * + * @return true if the range of characters requires bidi analysis + * + * @stable ICU 3.8 + */ + public static boolean requiresBidi(char[] text, int start, int limit) { + final int RTLMask = (1 << R | 1 << AL | 1 << RLE | 1 << RLO | 1 << AN); + + if (0 > start || start > limit || limit > text.length) { + throw new IllegalArgumentException("Value start " + start + " is out of range 0 to " + limit + ", or limit " + + limit + " is beyond the text length " + text.length); + } + + for (int i = start; i < limit; ++i) { + if (Character.isHighSurrogate(text[i]) && i < (limit - 1) && Character.isLowSurrogate(text[i + 1])) { + if (((1 << UCharacter.getDirection(Character.codePointAt(text, i))) & RTLMask) != 0) { + return true; + } + } else if (((1 << UCharacter.getDirection(text[i])) & RTLMask) != 0) { + return true; + } + } + + return false; + } + + /** + * Reorder the objects in the array into visual order based on their levels. + * This is a utility method to use when you have a collection of objects + * representing runs of text in logical order, each run containing text at a + * single level. The elements at index from + * objectStart up to objectStart + count in the + * objects array will be reordered into visual order assuming each run of text + * has the level indicated by the corresponding element in the levels array (at + * index - objectStart + levelStart). + * + * @param levels an array representing the bidi level of each object + * @param levelStart the start position in the levels array + * @param objects the array of objects to be reordered into visual order + * @param objectStart the start position in the objects array + * @param count the number of objects to reorder + * @stable ICU 3.8 + */ + public static void reorderVisually(byte[] levels, int levelStart, Object[] objects, int objectStart, int count) { + // for backward compatibility + if (0 > levelStart || levels.length <= levelStart) { + throw new IllegalArgumentException( + "Value levelStart " + levelStart + " is out of range 0 to " + (levels.length - 1)); + } + if (0 > objectStart || objects.length <= objectStart) { + throw new IllegalArgumentException( + "Value objectStart " + objectStart + " is out of range 0 to " + (objects.length - 1)); + } + if (0 > count || objects.length < (objectStart + count)) { + throw new IllegalArgumentException("Value count " + count + " is less than zero, or objectStart + count" + + " is beyond objects length " + objects.length); + } + + byte[] reorderLevels = new byte[count]; + System.arraycopy(levels, levelStart, reorderLevels, 0, count); + int[] indexMap = reorderVisual(reorderLevels); + Object[] temp = new Object[count]; + System.arraycopy(objects, objectStart, temp, 0, count); + for (int i = 0; i < count; ++i) { + objects[objectStart + i] = temp[indexMap[i]]; + } + } + + /** + * Take a Bidi object containing the reordering information for a + * piece of text (one or more paragraphs) set by setPara() or for a + * line of text set by setLine() and return a string containing the + * reordered text. + * + *

+ * The text may have been aliased (only a reference was stored without copying + * the contents), thus it must not have been modified since the + * setPara() call. + *

+ * + * This method preserves the integrity of characters with multiple code units + * and (optionally) combining characters. Characters in RTL runs can be replaced + * by mirror-image characters in the returned string. Note that "real" mirroring + * has to be done in a rendering engine by glyph selection and that for many + * "mirrored" characters there are no Unicode characters as mirror-image + * equivalents. There are also options to insert or remove Bidi control + * characters; see the descriptions of the return value and the + * options parameter, and of the option bit flags. + * + * @param options A bit set of options for the reordering that control how the + * reordered text is written. The options include mirroring the + * characters on a code point basis and inserting LRM characters, + * which is used especially for transforming visually stored text + * to logically stored text (although this is still an imperfect + * implementation of an "inverse Bidi" algorithm because it uses + * the "forward Bidi" algorithm at its core). The available + * options are: DO_MIRRORING, + * INSERT_LRM_FOR_NUMERIC, + * KEEP_BASE_COMBINING, OUTPUT_REVERSE, + * REMOVE_BIDI_CONTROLS, STREAMING + * + * @return The reordered text. If the INSERT_LRM_FOR_NUMERIC option + * is set, then the length of the returned string could be as large as + * getLength()+2*countRuns().
+ * If the REMOVE_BIDI_CONTROLS option is set, then the + * length of the returned string may be less than + * getLength().
+ * If none of these options is set, then the length of the returned + * string will be exactly getProcessedLength(). + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * + * @see #DO_MIRRORING + * @see #INSERT_LRM_FOR_NUMERIC + * @see #KEEP_BASE_COMBINING + * @see #OUTPUT_REVERSE + * @see #REMOVE_BIDI_CONTROLS + * @see #OPTION_STREAMING + * @see #getProcessedLength + * @stable ICU 3.8 + */ + public String writeReordered(int options) { + verifyValidParaOrLine(); + if (length == 0) { + /* nothing to do */ + return ""; + } + return BidiWriter.writeReordered(this, options); + } + + /** + * Display the bidi internal state, used in debugging. + */ + public String toString() { + StringBuilder buf = new StringBuilder(getClass().getName()); + + buf.append("[dir: "); + buf.append(direction); + buf.append(" baselevel: "); + buf.append(paraLevel); + buf.append(" length: "); + buf.append(length); + buf.append(" runs: "); + if (levels == null) { + buf.append("none"); + } else { + buf.append('['); + buf.append(levels[0]); + for (int i = 1; i < levels.length; i++) { + buf.append(' '); + buf.append(levels[i]); + } + buf.append(']'); + } + buf.append(" text: [0x"); + buf.append(Integer.toHexString(text[0])); + for (int i = 1; i < text.length; i++) { + buf.append(" 0x"); + buf.append(Integer.toHexString(text[i])); + } + buf.append("]]"); + + return buf.toString(); + } + +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/BidiLine.java b/src/main/java/jdk_internal/bidi/icu/text/BidiLine.java new file mode 100755 index 00000000..19d8e73e --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/BidiLine.java @@ -0,0 +1,821 @@ +/* + * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* +******************************************************************************* +* Copyright (C) 2001-2014, International Business Machines +* Corporation and others. All Rights Reserved. +******************************************************************************* +*/ +/* Written by Simon Montagu, Matitiahu Allouche + * (ported from C code written by Markus W. Scherer) + */ + +package jdk_internal.bidi.icu.text; + +import java.util.Arrays; + +import jdk_internal.bidi.Bidi; + +final class BidiLine { + + /* + * General remarks about the functions in this file: + * + * These functions deal with the aspects of potentially mixed-directional text + * in a single paragraph or in a line of a single paragraph which has already + * been processed according to the Unicode 3.0 Bidi algorithm as defined in Unicode Standard Annex #9: Unicode + * Bidirectional Algorithm, version 13, also described in The Unicode + * Standard, Version 4.0.1 . + * + * This means that there is a Bidi object with a levels and a dirProps array. + * paraLevel and direction are also set. Only if the length of the text is zero, + * then levels==dirProps==NULL. + * + * The overall directionality of the paragraph or line is used to bypass the + * reordering steps if possible. Even purely RTL text does not need reordering + * there because the getLogical/VisualIndex() methods can compute the index on + * the fly in such a case. + * + * The implementation of the access to same-level-runs and of the reordering do + * attempt to provide better performance and less memory usage compared to a + * direct implementation of especially rule (L2) with an array of one (32-bit) + * integer per text character. + * + * Here, the levels array is scanned as soon as necessary, and a vector of + * same-level-runs is created. Reordering then is done on this vector. For each + * run of text positions that were resolved to the same level, only 8 bytes are + * stored: the first text position of the run and the visual position behind the + * run after reordering. One sign bit is used to hold the directionality of the + * run. This is inefficient if there are many very short runs. If the average + * run length is <2, then this uses more memory. + * + * In a further attempt to save memory, the levels array is never changed after + * all the resolution rules (Xn, Wn, Nn, In). Many methods have to consider the + * field trailingWSStart: if it is less than length, then there is an implicit + * trailing run at the paraLevel, which is not reflected in the levels array. + * This allows a line Bidi object to use the same levels array as its paragraph + * parent object. + * + * When a Bidi object is created for a line of a paragraph, then the paragraph's + * levels and dirProps arrays are reused by way of setting a pointer into them, + * not by copying. This again saves memory and forbids to change the now shared + * levels for (L1). + */ + + /* handle trailing WS (L1) -------------------------------------------------- */ + + /* + * setTrailingWSStart() sets the start index for a trailing run of WS in the + * line. This is necessary because we do not modify the paragraph's levels array + * that we just point into. Using trailingWSStart is another form of performing + * (L1). + * + * To make subsequent operations easier, we also include the run before the WS + * if it is at the paraLevel - we merge the two here. + * + * This method is called only from setLine(), so paraLevel is set correctly for + * the line even when contextual multiple paragraphs. + */ + + static void setTrailingWSStart(BidiBase bidiBase) { + byte[] dirProps = bidiBase.dirProps; + byte[] levels = bidiBase.levels; + int start = bidiBase.length; + byte paraLevel = bidiBase.paraLevel; + + /* + * If the line is terminated by a block separator, all preceding WS etc... are + * already set to paragraph level. Setting trailingWSStart to pBidi->length will + * avoid changing the level of B chars from 0 to paraLevel in getLevels when + * orderParagraphsLTR==TRUE + */ + if (dirProps[start - 1] == BidiBase.B) { + bidiBase.trailingWSStart = start; /* currently == bidiBase.length */ + return; + } + /* go backwards across all WS, BN, explicit codes */ + while (start > 0 && (BidiBase.DirPropFlag(dirProps[start - 1]) & BidiBase.MASK_WS) != 0) { + --start; + } + + /* if the WS run can be merged with the previous run then do so here */ + while (start > 0 && levels[start - 1] == paraLevel) { + --start; + } + + bidiBase.trailingWSStart = start; + } + + static Bidi setLine(BidiBase paraBidi, Bidi newBidi, BidiBase lineBidi, int start, int limit) { + int length; + + /* set the values in lineBidi from its paraBidi parent */ + /* class members are already initialized to 0 */ + // lineBidi.paraBidi = null; /* mark unfinished setLine */ + // lineBidi.flags = 0; + // lineBidi.controlCount = 0; + + length = lineBidi.length = lineBidi.originalLength = lineBidi.resultLength = limit - start; + + lineBidi.text = new char[length]; + System.arraycopy(paraBidi.text, start, lineBidi.text, 0, length); + lineBidi.paraLevel = paraBidi.GetParaLevelAt(start); + lineBidi.paraCount = paraBidi.paraCount; + lineBidi.runs = new BidiRun[0]; + lineBidi.reorderingMode = paraBidi.reorderingMode; + lineBidi.reorderingOptions = paraBidi.reorderingOptions; + if (paraBidi.controlCount > 0) { + int j; + for (j = start; j < limit; j++) { + if (BidiBase.IsBidiControlChar(paraBidi.text[j])) { + lineBidi.controlCount++; + } + } + lineBidi.resultLength -= lineBidi.controlCount; + } + /* copy proper subset of DirProps */ + lineBidi.getDirPropsMemory(length); + lineBidi.dirProps = lineBidi.dirPropsMemory; + System.arraycopy(paraBidi.dirProps, start, lineBidi.dirProps, 0, length); + /* copy proper subset of Levels */ + lineBidi.getLevelsMemory(length); + lineBidi.levels = lineBidi.levelsMemory; + System.arraycopy(paraBidi.levels, start, lineBidi.levels, 0, length); + lineBidi.runCount = -1; + + if (paraBidi.direction != BidiBase.MIXED) { + /* the parent is already trivial */ + lineBidi.direction = paraBidi.direction; + + /* + * The parent's levels are all either implicitly or explicitly ==paraLevel; do + * the same here. + */ + if (paraBidi.trailingWSStart <= start) { + lineBidi.trailingWSStart = 0; + } else if (paraBidi.trailingWSStart < limit) { + lineBidi.trailingWSStart = paraBidi.trailingWSStart - start; + } else { + lineBidi.trailingWSStart = length; + } + } else { + byte[] levels = lineBidi.levels; + int i, trailingWSStart; + byte level; + + setTrailingWSStart(lineBidi); + trailingWSStart = lineBidi.trailingWSStart; + + /* recalculate lineBidiBase.direction */ + if (trailingWSStart == 0) { + /* all levels are at paraLevel */ + lineBidi.direction = (byte) (lineBidi.paraLevel & 1); + } else { + /* get the level of the first character */ + level = (byte) (levels[0] & 1); + + /* + * if there is anything of a different level, then the line is mixed + */ + if (trailingWSStart < length && (lineBidi.paraLevel & 1) != level) { + /* + * the trailing WS is at paraLevel, which differs from levels[0] + */ + lineBidi.direction = BidiBase.MIXED; + } else { + /* + * see if levels[1..trailingWSStart-1] have the same direction as levels[0] and + * paraLevel + */ + for (i = 1;; i++) { + if (i == trailingWSStart) { + /* the direction values match those in level */ + lineBidi.direction = level; + break; + } else if ((levels[i] & 1) != level) { + lineBidi.direction = BidiBase.MIXED; + break; + } + } + } + } + + switch (lineBidi.direction) { + case Bidi.DIRECTION_LEFT_TO_RIGHT: + /* make sure paraLevel is even */ + lineBidi.paraLevel = (byte) ((lineBidi.paraLevel + 1) & ~1); + + /* + * all levels are implicitly at paraLevel (important for getLevels()) + */ + lineBidi.trailingWSStart = 0; + break; + case Bidi.DIRECTION_RIGHT_TO_LEFT: + /* make sure paraLevel is odd */ + lineBidi.paraLevel |= 1; + + /* + * all levels are implicitly at paraLevel (important for getLevels()) + */ + lineBidi.trailingWSStart = 0; + break; + default: + break; + } + } + + lineBidi.paraBidi = paraBidi; /* mark successful setLine */ + + return newBidi; + } + + static byte getLevelAt(BidiBase bidiBase, int charIndex) { + /* return paraLevel if in the trailing WS run, otherwise the real level */ + if (bidiBase.direction != BidiBase.MIXED || charIndex >= bidiBase.trailingWSStart) { + return bidiBase.GetParaLevelAt(charIndex); + } else { + return bidiBase.levels[charIndex]; + } + } + + static byte[] getLevels(BidiBase bidiBase) { + int start = bidiBase.trailingWSStart; + int length = bidiBase.length; + + if (start != length) { + /* the current levels array does not reflect the WS run */ + /* + * After the previous if(), we know that the levels array has an implicit + * trailing WS run and therefore does not fully reflect itself all the levels. + * This must be a Bidi object for a line, and we need to create a new levels + * array. + */ + /* + * bidiBase.paraLevel is ok even if contextual multiple paragraphs, since + * bidiBase is a line object + */ + Arrays.fill(bidiBase.levels, start, length, bidiBase.paraLevel); + + /* this new levels array is set for the line and reflects the WS run */ + bidiBase.trailingWSStart = length; + } + if (length < bidiBase.levels.length) { + byte[] levels = new byte[length]; + System.arraycopy(bidiBase.levels, 0, levels, 0, length); + return levels; + } + return bidiBase.levels; + } + + static BidiRun getVisualRun(BidiBase bidiBase, int runIndex) { + int start = bidiBase.runs[runIndex].start; + int limit; + byte level = bidiBase.runs[runIndex].level; + + if (runIndex > 0) { + limit = start + bidiBase.runs[runIndex].limit - bidiBase.runs[runIndex - 1].limit; + } else { + limit = start + bidiBase.runs[0].limit; + } + return new BidiRun(start, limit, level); + } + + /* in trivial cases there is only one trivial run; called by getRuns() */ + private static void getSingleRun(BidiBase bidiBase, byte level) { + /* simple, single-run case */ + bidiBase.runs = bidiBase.simpleRuns; + bidiBase.runCount = 1; + + /* fill and reorder the single run */ + bidiBase.runs[0] = new BidiRun(0, bidiBase.length, level); + } + + /* reorder the runs array (L2) ---------------------------------------------- */ + + /* + * Reorder the same-level runs in the runs array. Here, runCount>1 and + * maxLevel>=minLevel>=paraLevel. All the visualStart fields=logical start + * before reordering. The "odd" bits are not set yet. + * + * Reordering with this data structure lends itself to some handy shortcuts: + * + * Since each run is moved but not modified, and since at the initial maxLevel + * each sequence of same-level runs consists of only one run each, we don't need + * to do anything there and can predecrement maxLevel. In many simple cases, the + * reordering is thus done entirely in the index mapping. Also, reordering + * occurs only down to the lowest odd level that occurs, which is minLevel|1. + * However, if the lowest level itself is odd, then in the last reordering the + * sequence of the runs at this level or higher will be all runs, and we don't + * need the elaborate loop to search for them. This is covered by ++minLevel + * instead of minLevel|=1 followed by an extra reorder-all after the + * reorder-some loop. About a trailing WS run: Such a run would need special + * treatment because its level is not reflected in levels[] if this is not a + * paragraph object. Instead, all characters from trailingWSStart on are + * implicitly at paraLevel. However, for all maxLevel>paraLevel, this run will + * never be reordered and does not need to be taken into account. + * maxLevel==paraLevel is only reordered if minLevel==paraLevel is odd, which is + * done in the extra segment. This means that for the main reordering loop we + * don't need to consider this run and can --runCount. If it is later part of + * the all-runs reordering, then runCount is adjusted accordingly. + */ + private static void reorderLine(BidiBase bidiBase, byte minLevel, byte maxLevel) { + + /* nothing to do? */ + if (maxLevel <= (minLevel | 1)) { + return; + } + + BidiRun[] runs; + BidiRun tempRun; + byte[] levels; + int firstRun, endRun, limitRun, runCount; + + /* + * Reorder only down to the lowest odd level and reorder at an odd minLevel in a + * separate, simpler loop. See comments above for why minLevel is always + * incremented. + */ + ++minLevel; + + runs = bidiBase.runs; + levels = bidiBase.levels; + runCount = bidiBase.runCount; + + /* + * do not include the WS run at paraLevel<=old minLevel except in the simple + * loop + */ + if (bidiBase.trailingWSStart < bidiBase.length) { + --runCount; + } + + while (--maxLevel >= minLevel) { + firstRun = 0; + + /* loop for all sequences of runs */ + for (;;) { + /* look for a sequence of runs that are all at >=maxLevel */ + /* look for the first run of such a sequence */ + while (firstRun < runCount && levels[runs[firstRun].start] < maxLevel) { + ++firstRun; + } + if (firstRun >= runCount) { + break; /* no more such runs */ + } + + /* look for the limit run of such a sequence (the run behind it) */ + for (limitRun = firstRun; ++limitRun < runCount && levels[runs[limitRun].start] >= maxLevel;) { + } + + /* Swap the entire sequence of runs from firstRun to limitRun-1. */ + endRun = limitRun - 1; + while (firstRun < endRun) { + tempRun = runs[firstRun]; + runs[firstRun] = runs[endRun]; + runs[endRun] = tempRun; + ++firstRun; + --endRun; + } + + if (limitRun == runCount) { + break; /* no more such runs */ + } else { + firstRun = limitRun + 1; + } + } + } + + /* now do maxLevel==old minLevel (==odd!), see above */ + if ((minLevel & 1) == 0) { + firstRun = 0; + + /* include the trailing WS run in this complete reordering */ + if (bidiBase.trailingWSStart == bidiBase.length) { + --runCount; + } + + /* Swap the entire sequence of all runs. (endRun==runCount) */ + while (firstRun < runCount) { + tempRun = runs[firstRun]; + runs[firstRun] = runs[runCount]; + runs[runCount] = tempRun; + ++firstRun; + --runCount; + } + } + } + + /* compute the runs array --------------------------------------------------- */ + + static int getRunFromLogicalIndex(BidiBase bidiBase, int logicalIndex) { + BidiRun[] runs = bidiBase.runs; + int runCount = bidiBase.runCount, visualStart = 0, i, length, logicalStart; + + for (i = 0; i < runCount; i++) { + length = runs[i].limit - visualStart; + logicalStart = runs[i].start; + if ((logicalIndex >= logicalStart) && (logicalIndex < (logicalStart + length))) { + return i; + } + visualStart += length; + } + /* we should never get here */ + throw new IllegalStateException("Internal ICU error in getRunFromLogicalIndex"); + } + + /* + * Compute the runs array from the levels array. After getRuns() returns true, + * runCount is guaranteed to be >0 and the runs are reordered. Odd-level runs + * have visualStart on their visual right edge and they progress visually to the + * left. If option OPTION_INSERT_MARKS is set, insertRemove will contain the sum + * of appropriate LRM/RLM_BEFORE/AFTER flags. If option OPTION_REMOVE_CONTROLS + * is set, insertRemove will contain the negative number of BiDi control + * characters within this run. + */ + static void getRuns(BidiBase bidiBase) { + /* + * This method returns immediately if the runs are already set. This includes + * the case of length==0 (handled in setPara).. + */ + if (bidiBase.runCount >= 0) { + return; + } + if (bidiBase.direction != BidiBase.MIXED) { + /* simple, single-run case - this covers length==0 */ + /* bidiBase.paraLevel is ok even for contextual multiple paragraphs */ + getSingleRun(bidiBase, bidiBase.paraLevel); + } else /* BidiBase.MIXED, length>0 */ { + /* mixed directionality */ + int length = bidiBase.length, limit; + byte[] levels = bidiBase.levels; + int i, runCount; + byte level = -1; /* initialize with no valid level */ + /* + * If there are WS characters at the end of the line and the run preceding them + * has a level different from paraLevel, then they will form their own run at + * paraLevel (L1). Count them separately. We need some special treatment for + * this in order to not modify the levels array which a line Bidi object shares + * with its paragraph parent and its other line siblings. In other words, for + * the trailing WS, it may be levels[]!=paraLevel but we have to treat it like + * it were so. + */ + limit = bidiBase.trailingWSStart; + /* count the runs, there is at least one non-WS run, and limit>0 */ + runCount = 0; + for (i = 0; i < limit; ++i) { + /* increment runCount at the start of each run */ + if (levels[i] != level) { + ++runCount; + level = levels[i]; + } + } + + /* + * We don't need to see if the last run can be merged with a trailing WS run + * because setTrailingWSStart() would have done that. + */ + if (runCount == 1 && limit == length) { + /* There is only one non-WS run and no trailing WS-run. */ + getSingleRun(bidiBase, levels[0]); + } else /* runCount>1 || limit 1 */ + bidiBase.getRunsMemory(runCount); + runs = bidiBase.runsMemory; + + /* set the runs */ + /* + * FOOD FOR THOUGHT: this could be optimized, e.g.: 464->444, 484->444, + * 575->555, 595->555 However, that would take longer. Check also how it would + * interact with BiDi control removal and inserting Marks. + */ + runIndex = 0; + + /* + * search for the run limits and initialize visualLimit values with the run + * lengths + */ + i = 0; + do { + /* prepare this run */ + start = i; + level = levels[i]; + if (level < minLevel) { + minLevel = level; + } + if (level > maxLevel) { + maxLevel = level; + } + + /* look for the run limit */ + while (++i < limit && levels[i] == level) { + } + + /* i is another run limit */ + runs[runIndex] = new BidiRun(start, i - start, level); + ++runIndex; + } while (i < limit); + + if (limit < length) { + /* there is a separate WS run */ + runs[runIndex] = new BidiRun(limit, length - limit, bidiBase.paraLevel); + /* + * For the trailing WS run, bidiBase.paraLevel is ok even if contextual multiple + * paragraphs. + */ + if (bidiBase.paraLevel < minLevel) { + minLevel = bidiBase.paraLevel; + } + } + + /* set the object fields */ + bidiBase.runs = runs; + bidiBase.runCount = runCount; + + reorderLine(bidiBase, minLevel, maxLevel); + + /* now add the direction flags and adjust the visualLimit's to be just that */ + /* this loop will also handle the trailing WS run */ + limit = 0; + for (i = 0; i < runCount; ++i) { + runs[i].level = levels[runs[i].start]; + limit = (runs[i].limit += limit); + } + + /* Set the embedding level for the trailing WS run. */ + /* For a RTL paragraph, it will be the *first* run in visual order. */ + /* + * For the trailing WS run, bidiBase.paraLevel is ok even if contextual multiple + * paragraphs. + */ + if (runIndex < runCount) { + int trailingRun = ((bidiBase.paraLevel & 1) != 0) ? 0 : runIndex; + runs[trailingRun].level = bidiBase.paraLevel; + } + } + } + + /* handle insert LRM/RLM BEFORE/AFTER run */ + if (bidiBase.insertPoints.size > 0) { + BidiBase.Point point; + int runIndex, ip; + for (ip = 0; ip < bidiBase.insertPoints.size; ip++) { + point = bidiBase.insertPoints.points[ip]; + runIndex = getRunFromLogicalIndex(bidiBase, point.pos); + bidiBase.runs[runIndex].insertRemove |= point.flag; + } + } + + /* handle remove BiDi control characters */ + if (bidiBase.controlCount > 0) { + int runIndex, ic; + char c; + for (ic = 0; ic < bidiBase.length; ic++) { + c = bidiBase.text[ic]; + if (BidiBase.IsBidiControlChar(c)) { + runIndex = getRunFromLogicalIndex(bidiBase, ic); + bidiBase.runs[runIndex].insertRemove--; + } + } + } + } + + static int[] prepareReorder(byte[] levels, byte[] pMinLevel, byte[] pMaxLevel) { + int start; + byte level, minLevel, maxLevel; + + if (levels == null || levels.length <= 0) { + return null; + } + + /* determine minLevel and maxLevel */ + minLevel = BidiBase.MAX_EXPLICIT_LEVEL + 1; + maxLevel = 0; + for (start = levels.length; start > 0;) { + level = levels[--start]; + if (level < 0 || level > (BidiBase.MAX_EXPLICIT_LEVEL + 1)) { + return null; + } + if (level < minLevel) { + minLevel = level; + } + if (level > maxLevel) { + maxLevel = level; + } + } + pMinLevel[0] = minLevel; + pMaxLevel[0] = maxLevel; + + /* initialize the index map */ + int[] indexMap = new int[levels.length]; + for (start = levels.length; start > 0;) { + --start; + indexMap[start] = start; + } + + return indexMap; + } + + static int[] reorderVisual(byte[] levels) { + byte[] aMinLevel = new byte[1]; + byte[] aMaxLevel = new byte[1]; + int start, end, limit, temp; + byte minLevel, maxLevel; + + int[] indexMap = prepareReorder(levels, aMinLevel, aMaxLevel); + if (indexMap == null) { + return null; + } + + minLevel = aMinLevel[0]; + maxLevel = aMaxLevel[0]; + + /* nothing to do? */ + if (minLevel == maxLevel && (minLevel & 1) == 0) { + return indexMap; + } + + /* reorder only down to the lowest odd level */ + minLevel |= 1; + + /* loop maxLevel..minLevel */ + do { + start = 0; + + /* loop for all sequences of levels to reorder at the current maxLevel */ + for (;;) { + /* look for a sequence of levels that are all at >=maxLevel */ + /* look for the first index of such a sequence */ + while (start < levels.length && levels[start] < maxLevel) { + ++start; + } + if (start >= levels.length) { + break; /* no more such runs */ + } + + /* look for the limit of such a sequence (the index behind it) */ + for (limit = start; ++limit < levels.length && levels[limit] >= maxLevel;) { + } + + /* + * Swap the entire interval of indexes from start to limit-1. We don't need to + * swap the levels for the purpose of this algorithm: the sequence of levels + * that we look at does not move anyway. + */ + end = limit - 1; + while (start < end) { + temp = indexMap[start]; + indexMap[start] = indexMap[end]; + indexMap[end] = temp; + + ++start; + --end; + } + + if (limit == levels.length) { + break; /* no more such sequences */ + } else { + start = limit + 1; + } + } + } while (--maxLevel >= minLevel); + + return indexMap; + } + + static int[] getVisualMap(BidiBase bidiBase) { + /* fill a visual-to-logical index map using the runs[] */ + BidiRun[] runs = bidiBase.runs; + int logicalStart, visualStart, visualLimit; + int allocLength = bidiBase.length > bidiBase.resultLength ? bidiBase.length : bidiBase.resultLength; + int[] indexMap = new int[allocLength]; + + visualStart = 0; + int idx = 0; + for (int j = 0; j < bidiBase.runCount; ++j) { + logicalStart = runs[j].start; + visualLimit = runs[j].limit; + if (runs[j].isEvenRun()) { + do { /* LTR */ + indexMap[idx++] = logicalStart++; + } while (++visualStart < visualLimit); + } else { + logicalStart += visualLimit - visualStart; /* logicalLimit */ + do { /* RTL */ + indexMap[idx++] = --logicalStart; + } while (++visualStart < visualLimit); + } + /* visualStart==visualLimit; */ + } + + if (bidiBase.insertPoints.size > 0) { + int markFound = 0, runCount = bidiBase.runCount; + int insertRemove, i, j, k; + runs = bidiBase.runs; + /* count all inserted marks */ + for (i = 0; i < runCount; i++) { + insertRemove = runs[i].insertRemove; + if ((insertRemove & (BidiBase.LRM_BEFORE | BidiBase.RLM_BEFORE)) > 0) { + markFound++; + } + if ((insertRemove & (BidiBase.LRM_AFTER | BidiBase.RLM_AFTER)) > 0) { + markFound++; + } + } + /* move back indexes by number of preceding marks */ + k = bidiBase.resultLength; + for (i = runCount - 1; i >= 0 && markFound > 0; i--) { + insertRemove = runs[i].insertRemove; + if ((insertRemove & (BidiBase.LRM_AFTER | BidiBase.RLM_AFTER)) > 0) { + indexMap[--k] = BidiBase.MAP_NOWHERE; + markFound--; + } + visualStart = i > 0 ? runs[i - 1].limit : 0; + for (j = runs[i].limit - 1; j >= visualStart && markFound > 0; j--) { + indexMap[--k] = indexMap[j]; + } + if ((insertRemove & (BidiBase.LRM_BEFORE | BidiBase.RLM_BEFORE)) > 0) { + indexMap[--k] = BidiBase.MAP_NOWHERE; + markFound--; + } + } + } else if (bidiBase.controlCount > 0) { + int runCount = bidiBase.runCount, logicalEnd; + int insertRemove, length, i, j, k, m; + char uchar; + boolean evenRun; + runs = bidiBase.runs; + visualStart = 0; + /* move forward indexes by number of preceding controls */ + k = 0; + for (i = 0; i < runCount; i++, visualStart += length) { + length = runs[i].limit - visualStart; + insertRemove = runs[i].insertRemove; + /* if no control found yet, nothing to do in this run */ + if ((insertRemove == 0) && (k == visualStart)) { + k += length; + continue; + } + /* if no control in this run */ + if (insertRemove == 0) { + visualLimit = runs[i].limit; + for (j = visualStart; j < visualLimit; j++) { + indexMap[k++] = indexMap[j]; + } + continue; + } + logicalStart = runs[i].start; + evenRun = runs[i].isEvenRun(); + logicalEnd = logicalStart + length - 1; + for (j = 0; j < length; j++) { + m = evenRun ? logicalStart + j : logicalEnd - j; + uchar = bidiBase.text[m]; + if (!BidiBase.IsBidiControlChar(uchar)) { + indexMap[k++] = m; + } + } + } + } + if (allocLength == bidiBase.resultLength) { + return indexMap; + } + int[] newMap = new int[bidiBase.resultLength]; + System.arraycopy(indexMap, 0, newMap, 0, bidiBase.resultLength); + return newMap; + } + +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/BidiRun.java b/src/main/java/jdk_internal/bidi/icu/text/BidiRun.java new file mode 100755 index 00000000..97b0e810 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/BidiRun.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + ******************************************************************************* + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* + */ +/* Written by Simon Montagu, Matitiahu Allouche + * (ported from C code written by Markus W. Scherer) + */ + +package jdk_internal.bidi.icu.text; + +/** + * A BidiRun represents a sequence of characters at the same embedding level. + * The Bidi algorithm decomposes a piece of text into sequences of characters at + * the same embedding level, each such sequence is called a "run". + * + *

+ * A BidiRun represents such a run by storing its essential properties, but does + * not duplicate the characters which form the run. + * + *

+ * The "limit" of the run is the position just after the last + * character, i.e., one more than that position. + * + *

+ * This class has no public constructor, and its members cannot be modified by + * users. + * + * @see com.ibm.icu.text.Bidi + */ +class BidiRun { + + int start; /* first logical position of the run */ + int limit; /* last visual position of the run +1 */ + int insertRemove; /* + * if >0, flags for inserting LRM/RLM before/after run, if <0, count of bidi + * controls within run + */ + byte level; + + /* + * Default constructor + * + * Note that members start and limit of a run instance have different meanings + * depending whether the run is part of the runs array of a Bidi object, or if + * it is a reference returned by getVisualRun() or getLogicalRun(). For a member + * of the runs array of a Bidi object, - start is the first logical position of + * the run in the source text. - limit is one after the last visual position of + * the run. For a reference returned by getLogicalRun() or getVisualRun(), - + * start is the first logical position of the run in the source text. - limit is + * one after the last logical position of the run. + */ + BidiRun() { + this(0, 0, (byte) 0); + } + + /* + * Constructor + */ + BidiRun(int start, int limit, byte embeddingLevel) { + this.start = start; + this.limit = limit; + this.level = embeddingLevel; + } + + /* + * Copy the content of a BidiRun instance + */ + void copyFrom(BidiRun run) { + this.start = run.start; + this.limit = run.limit; + this.level = run.level; + this.insertRemove = run.insertRemove; + } + + /** + * Get level of run + */ + byte getEmbeddingLevel() { + return level; + } + + /** + * Check if run level is even + * + * @return true if the embedding level of this run is even, i.e. it is a + * left-to-right run. + */ + boolean isEvenRun() { + return (level & 1) == 0; + } + +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/BidiWriter.java b/src/main/java/jdk_internal/bidi/icu/text/BidiWriter.java new file mode 100755 index 00000000..e9fa71e6 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/BidiWriter.java @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* +******************************************************************************* +* Copyright (C) 2001-2010, International Business Machines +* Corporation and others. All Rights Reserved. +******************************************************************************* +*/ +/* Written by Simon Montagu, Matitiahu Allouche + * (ported from C code written by Markus W. Scherer) + */ + +package jdk_internal.bidi.icu.text; + +import jdk_internal.bidi.icu.lang.UCharacter; + +final class BidiWriter { + + /** Bidi control code points */ + static final char LRM_CHAR = 0x200e; + static final char RLM_CHAR = 0x200f; + static final int MASK_R_AL = (1 << UCharacter.RIGHT_TO_LEFT | 1 << UCharacter.RIGHT_TO_LEFT_ARABIC); + + private static boolean IsCombining(int type) { + return ((1 << type & (1 << UCharacter.NON_SPACING_MARK | 1 << UCharacter.COMBINING_SPACING_MARK + | 1 << UCharacter.ENCLOSING_MARK)) != 0); + } + + /* + * When we have OUTPUT_REVERSE set on writeReordered(), then we semantically + * write RTL runs in reverse and later reverse them again. Instead, we actually + * write them in forward order to begin with. However, if the RTL run was to be + * mirrored, we need to mirror here now since the implicit second reversal must + * not do it. It looks strange to do mirroring in LTR output, but it is only + * because we are writing RTL output in reverse. + */ + private static String doWriteForward(String src, int options) { + /* optimize for several combinations of options */ + switch (options & (BidiBase.REMOVE_BIDI_CONTROLS | BidiBase.DO_MIRRORING)) { + case 0: { + /* simply return the LTR run */ + return src; + } + case BidiBase.DO_MIRRORING: { + StringBuffer dest = new StringBuffer(src.length()); + + /* do mirroring */ + int i = 0; + int c; + + do { + c = UTF16.charAt(src, i); + i += UTF16.getCharCount(c); + UTF16.append(dest, UCharacter.getMirror(c)); + } while (i < src.length()); + return dest.toString(); + } + case BidiBase.REMOVE_BIDI_CONTROLS: { + StringBuilder dest = new StringBuilder(src.length()); + + /* copy the LTR run and remove any Bidi control characters */ + int i = 0; + char c; + do { + c = src.charAt(i++); + if (!BidiBase.IsBidiControlChar(c)) { + dest.append(c); + } + } while (i < src.length()); + return dest.toString(); + } + default: { + StringBuffer dest = new StringBuffer(src.length()); + + /* remove Bidi control characters and do mirroring */ + int i = 0; + int c; + do { + c = UTF16.charAt(src, i); + i += UTF16.getCharCount(c); + if (!BidiBase.IsBidiControlChar(c)) { + UTF16.append(dest, UCharacter.getMirror(c)); + } + } while (i < src.length()); + return dest.toString(); + } + } /* end of switch */ + } + + private static String doWriteForward(char[] text, int start, int limit, int options) { + return doWriteForward(new String(text, start, limit - start), options); + } + + static String writeReverse(String src, int options) { + /* + * RTL run - + * + * RTL runs need to be copied to the destination in reverse order of code + * points, not code units, to keep Unicode characters intact. + * + * The general strategy for this is to read the source text in backward order, + * collect all code units for a code point (and optionally following combining + * characters, see below), and copy all these code units in ascending order to + * the destination for this run. + * + * Several options request whether combining characters should be kept after + * their base characters, whether Bidi control characters should be removed, and + * whether characters should be replaced by their mirror-image equivalent + * Unicode characters. + */ + StringBuffer dest = new StringBuffer(src.length()); + + /* optimize for several combinations of options */ + switch (options & (BidiBase.REMOVE_BIDI_CONTROLS | BidiBase.DO_MIRRORING | BidiBase.KEEP_BASE_COMBINING)) { + + case 0: + /* + * With none of the "complicated" options set, the destination run will have the + * same length as the source run, and there is no mirroring and no keeping + * combining characters with their base characters. + * + * XXX: or dest = UTF16.reverse(new StringBuffer(src)); + */ + + int srcLength = src.length(); + + /* preserve character integrity */ + do { + /* + * i is always after the last code unit known to need to be kept in this segment + */ + int i = srcLength; + + /* collect code units for one base character */ + srcLength -= UTF16.getCharCount(UTF16.charAt(src, srcLength - 1)); + + /* copy this base character */ + dest.append(src.substring(srcLength, i)); + } while (srcLength > 0); + break; + + case BidiBase.KEEP_BASE_COMBINING: + /* + * Here, too, the destination run will have the same length as the source run, + * and there is no mirroring. We do need to keep combining characters with their + * base characters. + */ + srcLength = src.length(); + + /* preserve character integrity */ + do { + /* + * i is always after the last code unit known to need to be kept in this segment + */ + int c; + int i = srcLength; + + /* + * collect code units and modifier letters for one base character + */ + do { + c = UTF16.charAt(src, srcLength - 1); + srcLength -= UTF16.getCharCount(c); + } while (srcLength > 0 && IsCombining(UCharacter.getType(c))); + + /* copy this "user character" */ + dest.append(src.substring(srcLength, i)); + } while (srcLength > 0); + break; + + default: + /* + * With several "complicated" options set, this is the most general and the + * slowest copying of an RTL run. We will do mirroring, remove Bidi controls, + * and keep combining characters with their base characters as requested. + */ + srcLength = src.length(); + + /* preserve character integrity */ + do { + /* + * i is always after the last code unit known to need to be kept in this segment + */ + int i = srcLength; + + /* collect code units for one base character */ + int c = UTF16.charAt(src, srcLength - 1); + srcLength -= UTF16.getCharCount(c); + if ((options & BidiBase.KEEP_BASE_COMBINING) != 0) { + /* collect modifier letters for this base character */ + while (srcLength > 0 && IsCombining(UCharacter.getType(c))) { + c = UTF16.charAt(src, srcLength - 1); + srcLength -= UTF16.getCharCount(c); + } + } + + if ((options & BidiBase.REMOVE_BIDI_CONTROLS) != 0 && BidiBase.IsBidiControlChar(c)) { + /* do not copy this Bidi control character */ + continue; + } + + /* copy this "user character" */ + int j = srcLength; + if ((options & BidiBase.DO_MIRRORING) != 0) { + /* mirror only the base character */ + c = UCharacter.getMirror(c); + UTF16.append(dest, c); + j += UTF16.getCharCount(c); + } + dest.append(src.substring(j, i)); + } while (srcLength > 0); + break; + } /* end of switch */ + + return dest.toString(); + } + + static String doWriteReverse(char[] text, int start, int limit, int options) { + return writeReverse(new String(text, start, limit - start), options); + } + + static String writeReordered(BidiBase bidi, int options) { + int run, runCount; + StringBuilder dest; + char[] text = bidi.text; + runCount = bidi.countRuns(); + + /* + * Option "insert marks" implies BidiBase.INSERT_LRM_FOR_NUMERIC if the + * reordering mode (checked below) is appropriate. + */ + if ((bidi.reorderingOptions & BidiBase.OPTION_INSERT_MARKS) != 0) { + options |= BidiBase.INSERT_LRM_FOR_NUMERIC; + options &= ~BidiBase.REMOVE_BIDI_CONTROLS; + } + /* + * Option "remove controls" implies BidiBase.REMOVE_BIDI_CONTROLS and cancels + * BidiBase.INSERT_LRM_FOR_NUMERIC. + */ + if ((bidi.reorderingOptions & BidiBase.OPTION_REMOVE_CONTROLS) != 0) { + options |= BidiBase.REMOVE_BIDI_CONTROLS; + options &= ~BidiBase.INSERT_LRM_FOR_NUMERIC; + } + /* + * If we do not perform the "inverse Bidi" algorithm, then we don't need to + * insert any LRMs, and don't need to test for it. + */ + if ((bidi.reorderingMode != BidiBase.REORDER_INVERSE_NUMBERS_AS_L) + && (bidi.reorderingMode != BidiBase.REORDER_INVERSE_LIKE_DIRECT) + && (bidi.reorderingMode != BidiBase.REORDER_INVERSE_FOR_NUMBERS_SPECIAL) + && (bidi.reorderingMode != BidiBase.REORDER_RUNS_ONLY)) { + options &= ~BidiBase.INSERT_LRM_FOR_NUMERIC; + } + dest = new StringBuilder((options & BidiBase.INSERT_LRM_FOR_NUMERIC) != 0 ? bidi.length * 2 : bidi.length); + /* + * Iterate through all visual runs and copy the run text segments to the + * destination, according to the options. + * + * The tests for where to insert LRMs ignore the fact that there may be BN codes + * or non-BMP code points at the beginning and end of a run; they may insert + * LRMs unnecessarily but the tests are faster this way (this would have to be + * improved for UTF-8). + */ + if ((options & BidiBase.OUTPUT_REVERSE) == 0) { + /* forward output */ + if ((options & BidiBase.INSERT_LRM_FOR_NUMERIC) == 0) { + /* do not insert Bidi controls */ + for (run = 0; run < runCount; ++run) { + BidiRun bidiRun = bidi.getVisualRun(run); + if (bidiRun.isEvenRun()) { + dest.append( + doWriteForward(text, bidiRun.start, bidiRun.limit, options & ~BidiBase.DO_MIRRORING)); + } else { + dest.append(doWriteReverse(text, bidiRun.start, bidiRun.limit, options)); + } + } + } else { + /* insert Bidi controls for "inverse Bidi" */ + byte[] dirProps = bidi.dirProps; + char uc; + int markFlag; + + for (run = 0; run < runCount; ++run) { + BidiRun bidiRun = bidi.getVisualRun(run); + markFlag = 0; + /* check if something relevant in insertPoints */ + markFlag = bidi.runs[run].insertRemove; + if (markFlag < 0) { /* bidi controls count */ + markFlag = 0; + } + if (bidiRun.isEvenRun()) { + if (bidi.isInverse() && dirProps[bidiRun.start] != BidiBase.L) { + markFlag |= BidiBase.LRM_BEFORE; + } + if ((markFlag & BidiBase.LRM_BEFORE) != 0) { + uc = LRM_CHAR; + } else if ((markFlag & BidiBase.RLM_BEFORE) != 0) { + uc = RLM_CHAR; + } else { + uc = 0; + } + if (uc != 0) { + dest.append(uc); + } + dest.append( + doWriteForward(text, bidiRun.start, bidiRun.limit, options & ~BidiBase.DO_MIRRORING)); + + if (bidi.isInverse() && dirProps[bidiRun.limit - 1] != BidiBase.L) { + markFlag |= BidiBase.LRM_AFTER; + } + if ((markFlag & BidiBase.LRM_AFTER) != 0) { + uc = LRM_CHAR; + } else if ((markFlag & BidiBase.RLM_AFTER) != 0) { + uc = RLM_CHAR; + } else { + uc = 0; + } + if (uc != 0) { + dest.append(uc); + } + } else { /* RTL run */ + if (bidi.isInverse() && !bidi.testDirPropFlagAt(MASK_R_AL, bidiRun.limit - 1)) { + markFlag |= BidiBase.RLM_BEFORE; + } + if ((markFlag & BidiBase.LRM_BEFORE) != 0) { + uc = LRM_CHAR; + } else if ((markFlag & BidiBase.RLM_BEFORE) != 0) { + uc = RLM_CHAR; + } else { + uc = 0; + } + if (uc != 0) { + dest.append(uc); + } + dest.append(doWriteReverse(text, bidiRun.start, bidiRun.limit, options)); + + if (bidi.isInverse() && (MASK_R_AL & BidiBase.DirPropFlag(dirProps[bidiRun.start])) == 0) { + markFlag |= BidiBase.RLM_AFTER; + } + if ((markFlag & BidiBase.LRM_AFTER) != 0) { + uc = LRM_CHAR; + } else if ((markFlag & BidiBase.RLM_AFTER) != 0) { + uc = RLM_CHAR; + } else { + uc = 0; + } + if (uc != 0) { + dest.append(uc); + } + } + } + } + } else { + /* reverse output */ + if ((options & BidiBase.INSERT_LRM_FOR_NUMERIC) == 0) { + /* do not insert Bidi controls */ + for (run = runCount; --run >= 0;) { + BidiRun bidiRun = bidi.getVisualRun(run); + if (bidiRun.isEvenRun()) { + dest.append( + doWriteReverse(text, bidiRun.start, bidiRun.limit, options & ~BidiBase.DO_MIRRORING)); + } else { + dest.append(doWriteForward(text, bidiRun.start, bidiRun.limit, options)); + } + } + } else { + /* insert Bidi controls for "inverse Bidi" */ + + byte[] dirProps = bidi.dirProps; + + for (run = runCount; --run >= 0;) { + /* reverse output */ + BidiRun bidiRun = bidi.getVisualRun(run); + if (bidiRun.isEvenRun()) { + if (dirProps[bidiRun.limit - 1] != BidiBase.L) { + dest.append(LRM_CHAR); + } + + dest.append( + doWriteReverse(text, bidiRun.start, bidiRun.limit, options & ~BidiBase.DO_MIRRORING)); + + if (dirProps[bidiRun.start] != BidiBase.L) { + dest.append(LRM_CHAR); + } + } else { + if ((MASK_R_AL & BidiBase.DirPropFlag(dirProps[bidiRun.start])) == 0) { + dest.append(RLM_CHAR); + } + + dest.append(doWriteForward(text, bidiRun.start, bidiRun.limit, options)); + + if ((MASK_R_AL & BidiBase.DirPropFlag(dirProps[bidiRun.limit - 1])) == 0) { + dest.append(RLM_CHAR); + } + } + } + } + } + + return dest.toString(); + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/FilteredNormalizer2.java b/src/main/java/jdk_internal/bidi/icu/text/FilteredNormalizer2.java new file mode 100755 index 00000000..3f9046bb --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/FilteredNormalizer2.java @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* +******************************************************************************* +* Copyright (C) 2009-2014, International Business Machines +* Corporation and others. All Rights Reserved. +******************************************************************************* +*/ +package jdk_internal.bidi.icu.text; + +import java.io.IOException; + +/** + * Normalization filtered by a UnicodeSet. Normalizes portions of the text + * contained in the filter set and leaves portions not contained in the filter + * set unchanged. Filtering is done via UnicodeSet.span(..., + * UnicodeSet.SpanCondition.SIMPLE). Not-in-the-filter text is treated as "is + * normalized" and "quick check yes". This class implements all of (and only) + * the Normalizer2 API. An instance of this class is unmodifiable/immutable. + * + * @stable ICU 4.4 + * @author Markus W. Scherer + */ +class FilteredNormalizer2 extends Normalizer2 { + + /** + * Constructs a filtered normalizer wrapping any Normalizer2 instance and a + * filter set. Both are aliased and must not be modified or deleted while this + * object is used. The filter set should be frozen; otherwise the performance + * will suffer greatly. + * + * @param n2 wrapped Normalizer2 instance + * @param filterSet UnicodeSet which determines the characters to be normalized + * @stable ICU 4.4 + */ + public FilteredNormalizer2(Normalizer2 n2, UnicodeSet filterSet) { + norm2 = n2; + set = filterSet; + } + + /** + * {@inheritDoc} + * + * @stable ICU 4.4 + */ + @Override + public StringBuilder normalize(CharSequence src, StringBuilder dest) { + if (dest == src) { + throw new IllegalArgumentException(); + } + dest.setLength(0); + normalize(src, dest, UnicodeSet.SpanCondition.SIMPLE); + return dest; + } + + /** + * {@inheritDoc} + * + * @stable ICU 4.6 + */ + @Override + public Appendable normalize(CharSequence src, Appendable dest) { + if (dest == src) { + throw new IllegalArgumentException(); + } + return normalize(src, dest, UnicodeSet.SpanCondition.SIMPLE); + } + + /** + * {@inheritDoc} + * + * @stable ICU 4.4 + */ + @Override + public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) { + return normalizeSecondAndAppend(first, second, true); + } + + /** + * {@inheritDoc} + * + * @stable ICU 4.4 + */ + @Override + public StringBuilder append(StringBuilder first, CharSequence second) { + return normalizeSecondAndAppend(first, second, false); + } + + /** + * {@inheritDoc} + * + * @stable ICU 4.6 + */ + @Override + public String getDecomposition(int c) { + return set.contains(c) ? norm2.getDecomposition(c) : null; + } + + /** + * {@inheritDoc} + * + * @stable ICU 49 + */ + @Override + public int getCombiningClass(int c) { + return set.contains(c) ? norm2.getCombiningClass(c) : 0; + } + + /** + * {@inheritDoc} + * + * @stable ICU 4.4 + */ + @Override + public boolean isNormalized(CharSequence s) { + UnicodeSet.SpanCondition spanCondition = UnicodeSet.SpanCondition.SIMPLE; + for (int prevSpanLimit = 0; prevSpanLimit < s.length();) { + int spanLimit = set.span(s, prevSpanLimit, spanCondition); + if (spanCondition == UnicodeSet.SpanCondition.NOT_CONTAINED) { + spanCondition = UnicodeSet.SpanCondition.SIMPLE; + } else { + if (!norm2.isNormalized(s.subSequence(prevSpanLimit, spanLimit))) { + return false; + } + spanCondition = UnicodeSet.SpanCondition.NOT_CONTAINED; + } + prevSpanLimit = spanLimit; + } + return true; + } + + /** + * {@inheritDoc} + * + * @stable ICU 4.4 + */ + @Override + public int spanQuickCheckYes(CharSequence s) { + UnicodeSet.SpanCondition spanCondition = UnicodeSet.SpanCondition.SIMPLE; + for (int prevSpanLimit = 0; prevSpanLimit < s.length();) { + int spanLimit = set.span(s, prevSpanLimit, spanCondition); + if (spanCondition == UnicodeSet.SpanCondition.NOT_CONTAINED) { + spanCondition = UnicodeSet.SpanCondition.SIMPLE; + } else { + int yesLimit = prevSpanLimit + norm2.spanQuickCheckYes(s.subSequence(prevSpanLimit, spanLimit)); + if (yesLimit < spanLimit) { + return yesLimit; + } + spanCondition = UnicodeSet.SpanCondition.NOT_CONTAINED; + } + prevSpanLimit = spanLimit; + } + return s.length(); + } + + /** + * {@inheritDoc} + * + * @stable ICU 4.4 + */ + @Override + public boolean hasBoundaryBefore(int c) { + return !set.contains(c) || norm2.hasBoundaryBefore(c); + } + + // Internal: No argument checking, and appends to dest. + // Pass as input spanCondition the one that is likely to yield a non-zero + // span length at the start of src. + // For set=[:age=3.2:], since almost all common characters were in Unicode 3.2, + // UnicodeSet.SpanCondition.SIMPLE should be passed in for the start of src + // and UnicodeSet.SpanCondition.NOT_CONTAINED should be passed in if we continue + // after + // an in-filter prefix. + private Appendable normalize(CharSequence src, Appendable dest, UnicodeSet.SpanCondition spanCondition) { + // Don't throw away destination buffer between iterations. + StringBuilder tempDest = new StringBuilder(); + try { + for (int prevSpanLimit = 0; prevSpanLimit < src.length();) { + int spanLimit = set.span(src, prevSpanLimit, spanCondition); + int spanLength = spanLimit - prevSpanLimit; + if (spanCondition == UnicodeSet.SpanCondition.NOT_CONTAINED) { + if (spanLength != 0) { + dest.append(src, prevSpanLimit, spanLimit); + } + spanCondition = UnicodeSet.SpanCondition.SIMPLE; + } else { + if (spanLength != 0) { + // Not norm2.normalizeSecondAndAppend() because we do not want + // to modify the non-filter part of dest. + dest.append(norm2.normalize(src.subSequence(prevSpanLimit, spanLimit), tempDest)); + } + spanCondition = UnicodeSet.SpanCondition.NOT_CONTAINED; + } + prevSpanLimit = spanLimit; + } + } catch (IOException e) { + throw new InternalError(e.toString(), e); + } + return dest; + } + + private StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second, boolean doNormalize) { + if (first == second) { + throw new IllegalArgumentException(); + } + if (first.length() == 0) { + if (doNormalize) { + return normalize(second, first); + } else { + return first.append(second); + } + } + // merge the in-filter suffix of the first string with the in-filter prefix of + // the second + int prefixLimit = set.span(second, 0, UnicodeSet.SpanCondition.SIMPLE); + if (prefixLimit != 0) { + CharSequence prefix = second.subSequence(0, prefixLimit); + int suffixStart = set.spanBack(first, 0x7fffffff, UnicodeSet.SpanCondition.SIMPLE); + if (suffixStart == 0) { + if (doNormalize) { + norm2.normalizeSecondAndAppend(first, prefix); + } else { + norm2.append(first, prefix); + } + } else { + StringBuilder middle = new StringBuilder(first.subSequence(suffixStart, first.length())); + if (doNormalize) { + norm2.normalizeSecondAndAppend(middle, prefix); + } else { + norm2.append(middle, prefix); + } + first.delete(suffixStart, 0x7fffffff).append(middle); + } + } + if (prefixLimit < second.length()) { + CharSequence rest = second.subSequence(prefixLimit, second.length()); + if (doNormalize) { + normalize(rest, first, UnicodeSet.SpanCondition.NOT_CONTAINED); + } else { + first.append(rest); + } + } + return first; + } + + private Normalizer2 norm2; + private UnicodeSet set; +}; diff --git a/src/main/java/jdk_internal/bidi/icu/text/Normalizer2.java b/src/main/java/jdk_internal/bidi/icu/text/Normalizer2.java new file mode 100755 index 00000000..f833478f --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/Normalizer2.java @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2014, International Business Machines + * Corporation and others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.text; + +import jdk_internal.bidi.icu.impl.Norm2AllModes; + +/** + * Unicode normalization functionality for standard Unicode normalization or for + * using custom mapping tables. All instances of this class are + * unmodifiable/immutable. The Normalizer2 class is not intended for public + * subclassing. + *

+ * The primary functions are to produce a normalized string and to detect + * whether a string is already normalized. The most commonly used normalization + * forms are those defined in + * Unicode Standard Annex #15: + * Unicode Normalization Forms. However, this API supports additional + * normalization forms for specialized purposes. For example, NFKC_Casefold is + * provided via getInstance("nfkc_cf", COMPOSE) and can be used in + * implementations of UTS #46. + *

+ * Not only are the standard compose and decompose modes supplied, but + * additional modes are provided as documented in the Mode enum. + *

+ * Some of the functions in this class identify normalization boundaries. At a + * normalization boundary, the portions of the string before it and starting + * from it do not interact and can be handled independently. + *

+ * The spanQuickCheckYes() stops at a normalization boundary. When the goal is a + * normalized string, then the text before the boundary can be copied, and the + * remainder can be processed with normalizeSecondAndAppend(). + *

+ * The hasBoundaryBefore(), hasBoundaryAfter() and isInert() functions test + * whether a character is guaranteed to be at a normalization boundary, + * regardless of context. This is used for moving from one normalization + * boundary to the next or preceding boundary, and for performing iterative + * normalization. + *

+ * Iterative normalization is useful when only a small portion of a longer + * string needs to be processed. For example, in ICU, iterative normalization is + * used by the NormalizationTransliterator (to avoid replacing + * already-normalized text) and ucol_nextSortKeyPart() (to process only the + * substring for which sort key bytes are computed). + *

+ * The set of normalization boundaries returned by these functions may not be + * complete: There may be more boundaries that could be returned. Different + * functions may return different boundaries. + * + * @stable ICU 4.4 + * @author Markus W. Scherer + */ +public abstract class Normalizer2 { + + /** + * Returns a Normalizer2 instance for Unicode NFC normalization. Same as + * getInstance(null, "nfc", Mode.COMPOSE). Returns an unmodifiable singleton + * instance. + * + * @return the requested Normalizer2, if successful + * @stable ICU 49 + */ + public static Normalizer2 getNFCInstance() { + return Norm2AllModes.getNFCInstance().comp; + } + + /** + * Returns a Normalizer2 instance for Unicode NFD normalization. Same as + * getInstance(null, "nfc", Mode.DECOMPOSE). Returns an unmodifiable singleton + * instance. + * + * @return the requested Normalizer2, if successful + * @stable ICU 49 + */ + public static Normalizer2 getNFDInstance() { + return Norm2AllModes.getNFCInstance().decomp; + } + + /** + * Returns a Normalizer2 instance for Unicode NFKC normalization. Same as + * getInstance(null, "nfkc", Mode.COMPOSE). Returns an unmodifiable singleton + * instance. + * + * @return the requested Normalizer2, if successful + * @stable ICU 49 + */ + public static Normalizer2 getNFKCInstance() { + return Norm2AllModes.getNFKCInstance().comp; + } + + /** + * Returns a Normalizer2 instance for Unicode NFKD normalization. Same as + * getInstance(null, "nfkc", Mode.DECOMPOSE). Returns an unmodifiable singleton + * instance. + * + * @return the requested Normalizer2, if successful + * @stable ICU 49 + */ + public static Normalizer2 getNFKDInstance() { + return Norm2AllModes.getNFKCInstance().decomp; + } + + /** + * Returns the normalized form of the source string. + * + * @param src source string + * @return normalized src + * @stable ICU 4.4 + */ + public String normalize(CharSequence src) { + if (src instanceof String) { + // Fastpath: Do not construct a new String if the src is a String + // and is already normalized. + int spanLength = spanQuickCheckYes(src); + if (spanLength == src.length()) { + return (String) src; + } + if (spanLength != 0) { + StringBuilder sb = new StringBuilder(src.length()).append(src, 0, spanLength); + return normalizeSecondAndAppend(sb, src.subSequence(spanLength, src.length())).toString(); + } + } + return normalize(src, new StringBuilder(src.length())).toString(); + } + + /** + * Writes the normalized form of the source string to the destination string + * (replacing its contents) and returns the destination string. The source and + * destination strings must be different objects. + * + * @param src source string + * @param dest destination string; its contents is replaced with normalized src + * @return dest + * @stable ICU 4.4 + */ + public abstract StringBuilder normalize(CharSequence src, StringBuilder dest); + + /** + * Writes the normalized form of the source string to the destination Appendable + * and returns the destination Appendable. The source and destination strings + * must be different objects. + * + *

+ * Any {@link java.io.IOException} is wrapped into a + * {@link com.ibm.icu.util.ICUUncheckedIOException}. + * + * @param src source string + * @param dest destination Appendable; gets normalized src appended + * @return dest + * @stable ICU 4.6 + */ + public abstract Appendable normalize(CharSequence src, Appendable dest); + + /** + * Appends the normalized form of the second string to the first string (merging + * them at the boundary) and returns the first string. The result is normalized + * if the first string was normalized. The first and second strings must be + * different objects. + * + * @param first string, should be normalized + * @param second string, will be normalized + * @return first + * @stable ICU 4.4 + */ + public abstract StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second); + + /** + * Appends the second string to the first string (merging them at the boundary) + * and returns the first string. The result is normalized if both the strings + * were normalized. The first and second strings must be different objects. + * + * @param first string, should be normalized + * @param second string, should be normalized + * @return first + * @stable ICU 4.4 + */ + public abstract StringBuilder append(StringBuilder first, CharSequence second); + + /** + * Gets the decomposition mapping of c. Roughly equivalent to normalizing the + * String form of c on a DECOMPOSE Normalizer2 instance, but much faster, and + * except that this function returns null if c does not have a decomposition + * mapping in this instance's data. This function is independent of the mode of + * the Normalizer2. + * + * @param c code point + * @return c's decomposition mapping, if any; otherwise null + * @stable ICU 4.6 + */ + public abstract String getDecomposition(int c); + + /** + * Gets the combining class of c. The default implementation returns 0 but all + * standard implementations return the Unicode Canonical_Combining_Class value. + * + * @param c code point + * @return c's combining class + * @stable ICU 49 + */ + public int getCombiningClass(int c) { + return 0; + } + + /** + * Tests if the string is normalized. Internally, in cases where the + * quickCheck() method would return "maybe" (which is only possible for the two + * COMPOSE modes) this method resolves to "yes" or "no" to provide a definitive + * result, at the cost of doing more work in those cases. + * + * @param s input string + * @return true if s is normalized + * @stable ICU 4.4 + */ + public abstract boolean isNormalized(CharSequence s); + + /** + * Returns the end of the normalized substring of the input string. In other + * words, with end=spanQuickCheckYes(s); the substring + * s.subSequence(0, end) will pass the quick check with a "yes" + * result. + *

+ * The returned end index is usually one or more characters before the "no" or + * "maybe" character: The end index is at a normalization boundary. (See the + * class documentation for more about normalization boundaries.) + *

+ * When the goal is a normalized string and most input strings are expected to + * be normalized already, then call this method, and if it returns a prefix + * shorter than the input string, copy that prefix and use + * normalizeSecondAndAppend() for the remainder. + * + * @param s input string + * @return "yes" span end index + * @stable ICU 4.4 + */ + public abstract int spanQuickCheckYes(CharSequence s); + + /** + * Tests if the character always has a normalization boundary before it, + * regardless of context. If true, then the character does not + * normalization-interact with preceding characters. In other words, a string + * containing this character can be normalized by processing portions before + * this character and starting from this character independently. This is used + * for iterative normalization. See the class documentation for details. + * + * @param c character to test + * @return true if c has a normalization boundary before it + * @stable ICU 4.4 + */ + public abstract boolean hasBoundaryBefore(int c); + + /** + * Sole constructor. (For invocation by subclass constructors, typically + * implicit.) + * + * @internal deprecated This API is ICU internal only. + */ + protected Normalizer2() { + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/NormalizerBase.java b/src/main/java/jdk_internal/bidi/icu/text/NormalizerBase.java new file mode 100755 index 00000000..5887aecb --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/NormalizerBase.java @@ -0,0 +1,791 @@ +/* + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2000-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ +package jdk_internal.bidi.icu.text; + +import jdk_internal.bidi.CharacterIterator; +import jdk_internal.bidi.Normalizer; +import jdk_internal.bidi.icu.impl.Norm2AllModes; + +/** + * Unicode Normalization + * + *

Unicode normalization API

+ * + * normalize transforms Unicode text into an equivalent composed or + * decomposed form, allowing for easier sorting and searching of text. + * normalize supports the standard normalization forms described in + * Unicode + * Standard Annex #15 — Unicode Normalization Forms. + * + * Characters with accents or other adornments can be encoded in several + * different ways in Unicode. For example, take the character A-acute. In + * Unicode, this can be encoded as a single character (the "composed" form): + * + *
+ *      00C1    LATIN CAPITAL LETTER A WITH ACUTE
+ * 
+ * + * or as two separate characters (the "decomposed" form): + * + *
+ *      0041    LATIN CAPITAL LETTER A
+ *      0301    COMBINING ACUTE ACCENT
+ * 
+ * + * To a user of your program, however, both of these sequences should be treated + * as the same "user-level" character "A with acute accent". When you are + * searching or comparing text, you must ensure that these two sequences are + * treated equivalently. In addition, you must handle characters with more than + * one accent. Sometimes the order of a character's combining accents is + * significant, while in other cases accent sequences in different orders are + * really equivalent. + * + * Similarly, the string "ffi" can be encoded as three separate letters: + * + *
+ *      0066    LATIN SMALL LETTER F
+ *      0066    LATIN SMALL LETTER F
+ *      0069    LATIN SMALL LETTER I
+ * 
+ * + * or as the single character + * + *
+ *      FB03    LATIN SMALL LIGATURE FFI
+ * 
+ * + * The ffi ligature is not a distinct semantic character, and strictly speaking + * it shouldn't be in Unicode at all, but it was included for compatibility with + * existing character sets that already provided it. The Unicode standard + * identifies such characters by giving them "compatibility" decompositions into + * the corresponding semantic characters. When sorting and searching, you will + * often want to use these mappings. + * + * normalize helps solve these problems by transforming text into + * the canonical composed and decomposed forms as shown in the first example + * above. In addition, you can have it perform compatibility decompositions so + * that you can treat compatibility characters the same as their equivalents. + * Finally, normalize rearranges accents into the proper canonical + * order, so that you do not have to worry about accent rearrangement on your + * own. + * + * Form FCD, "Fast C or D", is also designed for collation. It allows to work on + * strings that are not necessarily normalized with an algorithm (like in + * collation) that works under "canonical closure", i.e., it treats precomposed + * characters and their decomposed equivalents the same. + * + * It is not a normalization form because it does not provide for uniqueness of + * representation. Multiple strings may be canonically equivalent (their NFDs + * are identical) and may all conform to FCD without being identical themselves. + * + * The form is defined such that the "raw decomposition", the recursive + * canonical decomposition of each character, results in a string that is + * canonically ordered. This means that precomposed characters are allowed for + * as long as their decompositions do not need canonical reordering. + * + * Its advantage for a process like collation is that all NFD and most NFC texts + * - and many unnormalized texts - already conform to FCD and do not need to be + * normalized (NFD) for such a process. The FCD quick check will return YES for + * most strings in practice. + * + * normalize(FCD) may be implemented with NFD. + * + * For more details on FCD see Unicode Technical Note #5 (Canonical Equivalence + * in Applications): http://www.unicode.org/notes/tn5/#FCD + * + * ICU collation performs either NFD or FCD normalization automatically if + * normalization is turned on for the collator object. Beyond collation and + * string search, normalized strings may be useful for string equivalence + * comparisons, transliteration/transcription, unique representations, etc. + * + * The W3C generally recommends to exchange texts in NFC. Note also that most + * legacy character encodings use only precomposed forms and often do not encode + * any combining marks by themselves. For conversion to such character encodings + * the Unicode text needs to be normalized to NFC. For more usage examples, see + * the Unicode Standard Annex. + * + * Note: The Normalizer class also provides API for iterative normalization. + * While the setIndex() and getIndex() refer to indices in the underlying + * Unicode input text, the next() and previous() methods iterate through + * characters in the normalized output. This means that there is not necessarily + * a one-to-one correspondence between characters returned by next() and + * previous() and the indices passed to and returned from setIndex() and + * getIndex(). It is for this reason that Normalizer does not implement the + * CharacterIterator interface. + * + * @stable ICU 2.8 + */ +// Original filename in ICU4J: Normalizer.java +public final class NormalizerBase implements Cloneable { + + // The input text and our position in it + private UCharacterIterator text; + private Normalizer2 norm2; + private Mode mode; + private int options; + + // The normalization buffer is the result of normalization + // of the source in [currentIndex..nextIndex] . + private int currentIndex; + private int nextIndex; + + // A buffer for holding intermediate results + private StringBuilder buffer; + private int bufferPos; + + // Helper classes to defer loading of normalization data. + private static final class ModeImpl { + private ModeImpl(Normalizer2 n2) { + normalizer2 = n2; + } + + private final Normalizer2 normalizer2; + } + + private static final class NFDModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl(Normalizer2.getNFDInstance()); + } + + private static final class NFKDModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl(Normalizer2.getNFKDInstance()); + } + + private static final class NFCModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl(Normalizer2.getNFCInstance()); + } + + private static final class NFKCModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl(Normalizer2.getNFKCInstance()); + } + + private static final class Unicode32 { + private static final UnicodeSet INSTANCE = new UnicodeSet("[:age=3.2:]").freeze(); + } + + private static final class NFD32ModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl( + new FilteredNormalizer2(Normalizer2.getNFDInstance(), Unicode32.INSTANCE)); + } + + private static final class NFKD32ModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl( + new FilteredNormalizer2(Normalizer2.getNFKDInstance(), Unicode32.INSTANCE)); + } + + private static final class NFC32ModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl( + new FilteredNormalizer2(Normalizer2.getNFCInstance(), Unicode32.INSTANCE)); + } + + private static final class NFKC32ModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl( + new FilteredNormalizer2(Normalizer2.getNFKCInstance(), Unicode32.INSTANCE)); + } + + /** + * Options bit set value to select Unicode 3.2 normalization (except + * NormalizationCorrections). At most one Unicode version can be selected at a + * time. + * + * @stable ICU 2.6 + */ + public static final int UNICODE_3_2 = 0x20; + + public static final int UNICODE_3_2_0_ORIGINAL = UNICODE_3_2; + + /* + * Default option for the latest Unicode normalization. This option is provided + * mainly for testing. The value zero means that normalization is done with the + * fixes for - Corrigendum 4 (Five CJK Canonical Mapping Errors) - Corrigendum 5 + * (Normalization Idempotency) + */ + public static final int UNICODE_LATEST = 0x00; + + /** + * Constant indicating that the end of the iteration has been reached. This is + * guaranteed to have the same value as {@link UCharacterIterator#DONE}. + * + * @stable ICU 2.8 + */ + public static final int DONE = UCharacterIterator.DONE; + + /** + * Constants for normalization modes. + *

+ * The Mode class is not intended for public subclassing. Only the Mode + * constants provided by the Normalizer class should be used, and any fields or + * methods should not be called or overridden by users. + * + * @stable ICU 2.8 + */ + public abstract static class Mode { + + /** + * Sole constructor + * + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected Mode() { + } + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected abstract Normalizer2 getNormalizer2(int options); + } + + private static Mode toMode(Normalizer.Form form) { + switch (form) { + case NFC: + return NFC; + case NFD: + return NFD; + case NFKC: + return NFKC; + case NFKD: + return NFKD; + } + + throw new IllegalArgumentException("Unexpected normalization form: " + form); + } + + private static final class NONEMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { + return Norm2AllModes.NOOP_NORMALIZER2; + } + } + + private static final class NFDMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { + return (options & UNICODE_3_2) != 0 ? NFD32ModeImpl.INSTANCE.normalizer2 : NFDModeImpl.INSTANCE.normalizer2; + } + } + + private static final class NFKDMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { + return (options & UNICODE_3_2) != 0 ? NFKD32ModeImpl.INSTANCE.normalizer2 + : NFKDModeImpl.INSTANCE.normalizer2; + } + } + + private static final class NFCMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { + return (options & UNICODE_3_2) != 0 ? NFC32ModeImpl.INSTANCE.normalizer2 : NFCModeImpl.INSTANCE.normalizer2; + } + } + + private static final class NFKCMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { + return (options & UNICODE_3_2) != 0 ? NFKC32ModeImpl.INSTANCE.normalizer2 + : NFKCModeImpl.INSTANCE.normalizer2; + } + } + + /** + * No decomposition/composition. + * + * @stable ICU 2.8 + */ + public static final Mode NONE = new NONEMode(); + + /** + * Canonical decomposition. + * + * @stable ICU 2.8 + */ + public static final Mode NFD = new NFDMode(); + + /** + * Compatibility decomposition. + * + * @stable ICU 2.8 + */ + public static final Mode NFKD = new NFKDMode(); + + /** + * Canonical decomposition followed by canonical composition. + * + * @stable ICU 2.8 + */ + public static final Mode NFC = new NFCMode(); + + public static final Mode NFKC = new NFKCMode(); + + // ------------------------------------------------------------------------- + // Iterator constructors + // ------------------------------------------------------------------------- + + /** + * Creates a new {@code NormalizerBase} object for iterating over the normalized + * form of a given string. + *

+ * The {@code options} parameter specifies which optional {@code NormalizerBase} + * features are to be enabled for this object. + *

+ * + * @param str The string to be normalized. The normalization will start at the + * beginning of the string. + * + * @param mode The normalization mode. + * + * @param opt Any optional features to be enabled. Currently the only available + * option is {@link #UNICODE_3_2}. If you want the default behavior + * corresponding to one of the standard Unicode Normalization Forms, + * use 0 for this argument. + * @stable ICU 2.6 + */ + public NormalizerBase(String str, Mode mode, int opt) { + this.text = UCharacterIterator.getInstance(str); + this.mode = mode; + this.options = opt; + norm2 = mode.getNormalizer2(opt); + buffer = new StringBuilder(); + } + + public NormalizerBase(String str, Mode mode) { + this(str, mode, 0); + } + + /** + * Creates a new {@code NormalizerBase} object for iterating over the normalized + * form of the given text. + *

+ * + * @param iter The input text to be normalized. The normalization will start at + * the beginning of the string. + * + * @param mode The normalization mode. + * + * @param opt Any optional features to be enabled. Currently the only available + * option is {@link #UNICODE_3_2}. If you want the default behavior + * corresponding to one of the standard Unicode Normalization Forms, + * use 0 for this argument. + * @stable ICU 2.6 + */ + public NormalizerBase(CharacterIterator iter, Mode mode, int opt) { + this.text = UCharacterIterator.getInstance((CharacterIterator) iter.clone()); + this.mode = mode; + this.options = opt; + norm2 = mode.getNormalizer2(opt); + buffer = new StringBuilder(); + } + + public NormalizerBase(CharacterIterator iter, Mode mode) { + this(iter, mode, 0); + } + + /** + * Clones this {@code NormalizerBase} object. All properties of this object are + * duplicated in the new object, including the cloning of any + * {@link CharacterIterator} that was passed in to the constructor or to + * {@link #setText(CharacterIterator) setText}. However, the text storage + * underlying the {@code CharacterIterator} is not duplicated unless the + * iterator's {@code clone} method does so. + * + * @stable ICU 2.8 + */ + public Object clone() { + try { + NormalizerBase copy = (NormalizerBase) super.clone(); + copy.text = (UCharacterIterator) text.clone(); + copy.mode = mode; + copy.options = options; + copy.norm2 = norm2; + copy.buffer = new StringBuilder(buffer); + copy.bufferPos = bufferPos; + copy.currentIndex = currentIndex; + copy.nextIndex = nextIndex; + return copy; + } catch (CloneNotSupportedException e) { + throw new InternalError(e.toString(), e); + } + } + + /** + * Normalizes a {@code String} using the given normalization operation. + *

+ * The {@code options} parameter specifies which optional {@code NormalizerBase} + * features are to be enabled for this operation. Currently the only available + * option is {@link #UNICODE_3_2}. If you want the default behavior + * corresponding to one of the standard Unicode Normalization Forms, use 0 for + * this argument. + *

+ * + * @param str the input string to be normalized. + * @param mode the normalization mode + * @param options the optional features to be enabled. + * @return String the normalized string + * @stable ICU 2.6 + */ + public static String normalize(String str, Mode mode, int options) { + return mode.getNormalizer2(options).normalize(str); + } + + public static String normalize(String str, Normalizer.Form form) { + return NormalizerBase.normalize(str, toMode(form), UNICODE_LATEST); + } + + public static String normalize(String str, Normalizer.Form form, int options) { + return NormalizerBase.normalize(str, toMode(form), options); + } + + /** + * Test if a string is in a given normalization form. This is semantically + * equivalent to source.equals(normalize(source, mode)). + * + * Unlike quickCheck(), this function returns a definitive result, never a + * "maybe". For NFD, NFKD, and FCD, both functions work exactly the same. For + * NFC and NFKC where quickCheck may return "maybe", this function will perform + * further tests to arrive at a true/false result. + * + * @param str the input string to be checked to see if it is normalized + * @param mode the normalization mode + * @param options Options for use with exclusion set and tailored Normalization + * The only option that is currently recognized is UNICODE_3_2 + * @see #isNormalized + * @stable ICU 2.6 + */ + public static boolean isNormalized(String str, Mode mode, int options) { + return mode.getNormalizer2(options).isNormalized(str); + } + + public static boolean isNormalized(String str, Normalizer.Form form) { + return NormalizerBase.isNormalized(str, toMode(form), UNICODE_LATEST); + } + + public static boolean isNormalized(String str, Normalizer.Form form, int options) { + return NormalizerBase.isNormalized(str, toMode(form), options); + } + + // ------------------------------------------------------------------------- + // Iteration API + // ------------------------------------------------------------------------- + + /** + * Return the current character in the normalized text. + * + * @return The codepoint as an int + * @stable ICU 2.8 + */ + public int current() { + if (bufferPos < buffer.length() || nextNormalize()) { + return buffer.codePointAt(bufferPos); + } else { + return DONE; + } + } + + /** + * Return the next character in the normalized text and advance the iteration + * position by one. If the end of the text has already been reached, + * {@link #DONE} is returned. + * + * @return The codepoint as an int + * @stable ICU 2.8 + */ + public int next() { + if (bufferPos < buffer.length() || nextNormalize()) { + int c = buffer.codePointAt(bufferPos); + bufferPos += Character.charCount(c); + return c; + } else { + return DONE; + } + } + + /** + * Return the previous character in the normalized text and decrement the + * iteration position by one. If the beginning of the text has already been + * reached, {@link #DONE} is returned. + * + * @return The codepoint as an int + * @stable ICU 2.8 + */ + public int previous() { + if (bufferPos > 0 || previousNormalize()) { + int c = buffer.codePointBefore(bufferPos); + bufferPos -= Character.charCount(c); + return c; + } else { + return DONE; + } + } + + /** + * Reset the index to the beginning of the text. This is equivalent to + * setIndexOnly(startIndex)). + * + * @stable ICU 2.8 + */ + public void reset() { + text.setIndex(0); + currentIndex = nextIndex = 0; + clearBuffer(); + } + + /** + * Set the iteration position in the input text that is being normalized, + * without any immediate normalization. After setIndexOnly(), getIndex() will + * return the same index that is specified here. + * + * @param index the desired index in the input text. + * @stable ICU 2.8 + */ + public void setIndexOnly(int index) { + text.setIndex(index); // validates index + currentIndex = nextIndex = index; + clearBuffer(); + } + + /** + * Set the iteration position in the input text that is being normalized and + * return the first normalized character at that position. + *

+ * Note: This method sets the position in the input text, while + * {@link #next} and {@link #previous} iterate through characters in the + * normalized output. This means that there is not necessarily a + * one-to-one correspondence between characters returned by {@code next} and + * {@code previous} and the indices passed to and returned from {@code setIndex} + * and {@link #getIndex}. + *

+ * + * @param index the desired index in the input text. + * + * @return the first normalized character that is the result of iterating + * forward starting at the given index. + * + * @throws IllegalArgumentException if the given index is less than + * {@link #getBeginIndex} or greater than + * {@link #getEndIndex}. deprecated ICU 3.2 + * @obsolete ICU 3.2 + */ + public int setIndex(int index) { + setIndexOnly(index); + return current(); + } + + /** + * Retrieve the index of the start of the input text. This is the begin index of + * the {@code CharacterIterator} or the start (i.e. 0) of the {@code String} + * over which this {@code NormalizerBase} is iterating + * + * @deprecated ICU 2.2. Use startIndex() instead. + * @return The codepoint as an int + * @see #startIndex + */ + @Deprecated + public int getBeginIndex() { + return 0; + } + + /** + * Retrieve the index of the end of the input text. This is the end index of the + * {@code CharacterIterator} or the length of the {@code String} over which this + * {@code NormalizerBase} is iterating + * + * @deprecated ICU 2.2. Use endIndex() instead. + * @return The codepoint as an int + * @see #endIndex + */ + @Deprecated + public int getEndIndex() { + return endIndex(); + } + + /** + * Retrieve the current iteration position in the input text that is being + * normalized. This method is useful in applications such as searching, where + * you need to be able to determine the position in the input text that + * corresponds to a given normalized output character. + *

+ * Note: This method sets the position in the input, while + * {@link #next} and {@link #previous} iterate through characters in the + * output. This means that there is not necessarily a one-to-one + * correspondence between characters returned by {@code next} and + * {@code previous} and the indices passed to and returned from {@code setIndex} + * and {@link #getIndex}. + * + * @return The current iteration position + * @stable ICU 2.8 + */ + public int getIndex() { + if (bufferPos < buffer.length()) { + return currentIndex; + } else { + return nextIndex; + } + } + + /** + * Retrieve the index of the end of the input text. This is the end index of the + * {@code CharacterIterator} or the length of the {@code String} over which this + * {@code NormalizerBase} is iterating + * + * @return The current iteration position + * @stable ICU 2.8 + */ + public int endIndex() { + return text.getLength(); + } + + // ------------------------------------------------------------------------- + // Iterator attributes + // ------------------------------------------------------------------------- + /** + * Set the normalization mode for this object. + *

+ * Note:If the normalization mode is changed while iterating over a + * string, calls to {@link #next} and {@link #previous} may return previously + * buffers characters in the old normalization mode until the iteration is able + * to re-sync at the next base character. It is safest to call {@link #setText + * setText()}, {@link #first}, {@link #last}, etc. after calling + * {@code setMode}. + *

+ * + * @param newMode the new mode for this {@code NormalizerBase}. The supported + * modes are: + *

    + *
  • {@link #NFC} - Unicode canonical decompositiion followed + * by canonical composition. + *
  • {@link #NFKC} - Unicode compatibility decompositiion + * follwed by canonical composition. + *
  • {@link #NFD} - Unicode canonical decomposition + *
  • {@link #NFKD} - Unicode compatibility decomposition. + *
  • {@link #NONE} - Do nothing but return characters from the + * underlying input text. + *
+ * + * @see #getMode + * @stable ICU 2.8 + */ + public void setMode(Mode newMode) { + mode = newMode; + norm2 = mode.getNormalizer2(options); + } + + /** + * Return the basic operation performed by this {@code NormalizerBase} + * + * @see #setMode + * @stable ICU 2.8 + */ + public Mode getMode() { + return mode; + } + + /** + * Set the input text over which this {@code NormalizerBase} will iterate. The + * iteration position is set to the beginning of the input text. + * + * @param newText The new string to be normalized. + * @stable ICU 2.8 + */ + public void setText(String newText) { + UCharacterIterator newIter = UCharacterIterator.getInstance(newText); + if (newIter == null) { + throw new IllegalStateException("Could not create a new UCharacterIterator"); + } + text = newIter; + reset(); + } + + /** + * Set the input text over which this {@code NormalizerBase} will iterate. The + * iteration position is set to the beginning of the input text. + * + * @param newText The new string to be normalized. + * @stable ICU 2.8 + */ + public void setText(CharacterIterator newText) { + UCharacterIterator newIter = UCharacterIterator.getInstance(newText); + if (newIter == null) { + throw new IllegalStateException("Could not create a new UCharacterIterator"); + } + text = newIter; + currentIndex = nextIndex = 0; + clearBuffer(); + } + + private void clearBuffer() { + buffer.setLength(0); + bufferPos = 0; + } + + private boolean nextNormalize() { + clearBuffer(); + currentIndex = nextIndex; + text.setIndex(nextIndex); + // Skip at least one character so we make progress. + int c = text.nextCodePoint(); + if (c < 0) { + return false; + } + StringBuilder segment = new StringBuilder().appendCodePoint(c); + while ((c = text.nextCodePoint()) >= 0) { + if (norm2.hasBoundaryBefore(c)) { + text.moveCodePointIndex(-1); + break; + } + segment.appendCodePoint(c); + } + nextIndex = text.getIndex(); + norm2.normalize(segment, buffer); + return buffer.length() != 0; + } + + private boolean previousNormalize() { + clearBuffer(); + nextIndex = currentIndex; + text.setIndex(currentIndex); + StringBuilder segment = new StringBuilder(); + int c; + while ((c = text.previousCodePoint()) >= 0) { + if (c <= 0xffff) { + segment.insert(0, (char) c); + } else { + segment.insert(0, Character.toChars(c)); + } + if (norm2.hasBoundaryBefore(c)) { + break; + } + } + currentIndex = text.getIndex(); + norm2.normalize(segment, buffer); + bufferPos = buffer.length(); + return buffer.length() != 0; + } + +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/Replaceable.java b/src/main/java/jdk_internal/bidi/icu/text/Replaceable.java new file mode 100755 index 00000000..22c7fff6 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/Replaceable.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.text; + +/** + * Replaceable is an interface representing a string of characters + * that supports the replacement of a range of itself with a new string of + * characters. It is used by APIs that change a piece of text while retaining + * metadata. Metadata is data other than the Unicode characters returned by + * char32At(). One example of metadata is style attributes; another is an edit + * history, marking each character with an author and revision number. + * + *

+ * An implicit aspect of the Replaceable API is that during a + * replace operation, new characters take on the metadata of the old characters. + * For example, if the string "the bold font" has range (4, 8) replaced + * with "strong", then it becomes "the strong font". + * + *

+ * Replaceable specifies ranges using a start offset and a limit + * offset. The range of characters thus specified includes the characters at + * offset start..limit-1. That is, the start offset is inclusive, and the limit + * offset is exclusive. + * + *

+ * Replaceable also includes API to access characters in the + * string: length(), charAt(), + * char32At(), and extractBetween(). + * + *

+ * For a subclass to support metadata, typical behavior of + * replace() is the following: + *

    + *
  • Set the metadata of the new text to the metadata of the first character + * replaced
  • + *
  • If no characters are replaced, use the metadata of the previous + * character
  • + *
  • If there is no previous character (i.e. start == 0), use the following + * character
  • + *
  • If there is no following character (i.e. the replaceable was empty), use + * default metadata
  • + *
  • If the code point U+FFFF is seen, it should be interpreted as a special + * marker having no metadata
  • + *
+ * If this is not the behavior, the subclass should document any differences. + * + *

+ * Copyright © IBM Corporation 1999. All rights reserved. + * + * @author Alan Liu + * @stable ICU 2.0 + */ +public interface Replaceable { + /** + * Returns the number of 16-bit code units in the text. + * + * @return number of 16-bit code units in text + * @stable ICU 2.0 + */ + int length(); + + /** + * Returns the 16-bit code unit at the given offset into the text. + * + * @param offset an integer between 0 and length()-1 inclusive + * @return 16-bit code unit of text at given offset + * @stable ICU 2.0 + */ + char charAt(int offset); + + /** + * Copies characters from this object into the destination character array. The + * first character to be copied is at index srcStart; the last + * character to be copied is at index srcLimit-1 (thus the total + * number of characters to be copied is srcLimit-srcStart). The + * characters are copied into the subarray of dst starting at index + * dstStart and ending at index + * dstStart + (srcLimit-srcStart) - 1. + * + * @param srcStart the beginning index to copy, inclusive; + * {@code 0 <= start <= limit}. + * @param srcLimit the ending index to copy, exclusive; + * {@code start <= limit <= length()}. + * @param dst the destination array. + * @param dstStart the start offset in the destination array. + * @stable ICU 2.0 + */ + void getChars(int srcStart, int srcLimit, char dst[], int dstStart); +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/ReplaceableString.java b/src/main/java/jdk_internal/bidi/icu/text/ReplaceableString.java new file mode 100755 index 00000000..661eccac --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/ReplaceableString.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 1996-2009, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.text; + +/** + * ReplaceableString is an adapter class that implements the + * Replaceable API around an ordinary StringBuffer. + * + *

+ * Note: This class does not support attributes and is not intended for + * general use. Most clients will need to implement {@link Replaceable} in their + * text representation class. + * + *

+ * Copyright © IBM Corporation 1999. All rights reserved. + * + * @see Replaceable + * @author Alan Liu + * @stable ICU 2.0 + */ +public class ReplaceableString implements Replaceable { + + private StringBuffer buf; + + /** + * Construct a new object with the given initial contents. + * + * @param str initial contents + * @stable ICU 2.0 + */ + public ReplaceableString(String str) { + buf = new StringBuffer(str); + } + + /** + * Construct a new object using buf for internal storage. The + * contents of buf at the time of construction are used as the + * initial contents. Note! Modifications to buf will modify + * this object, and vice versa. + * + * @param buf object to be used as internal storage + * @stable ICU 2.0 + */ + public ReplaceableString(StringBuffer buf) { + this.buf = buf; + } + + /** + * Return the number of characters contained in this object. + * Replaceable API. + * + * @stable ICU 2.0 + */ + public int length() { + return buf.length(); + } + + /** + * Return the character at the given position in this object. + * Replaceable API. + * + * @param offset offset into the contents, from 0 to length() - 1 + * @stable ICU 2.0 + */ + public char charAt(int offset) { + return buf.charAt(offset); + } + + /** + * Copies characters from this object into the destination character array. The + * first character to be copied is at index srcStart; the last + * character to be copied is at index srcLimit-1 (thus the total + * number of characters to be copied is srcLimit-srcStart). The + * characters are copied into the subarray of dst starting at index + * dstStart and ending at index + * dstStart + (srcLimit-srcStart) - 1. + * + * @param srcStart the beginning index to copy, inclusive; + * {@code 0 <= start <= limit}. + * @param srcLimit the ending index to copy, exclusive; + * {@code start <= limit <= length()}. + * @param dst the destination array. + * @param dstStart the start offset in the destination array. + * @stable ICU 2.0 + */ + public void getChars(int srcStart, int srcLimit, char dst[], int dstStart) { + if (srcStart != srcLimit) { + buf.getChars(srcStart, srcLimit, dst, dstStart); + } + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/StringPrep.java b/src/main/java/jdk_internal/bidi/icu/text/StringPrep.java new file mode 100755 index 00000000..da41151a --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/StringPrep.java @@ -0,0 +1,493 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* +/* + ******************************************************************************* + * Copyright (C) 2003-2004, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ +// +// CHANGELOG +// 2005-05-19 Edward Wang +// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/text/StringPrep.java +// - move from package com.ibm.icu.text to package sun.net.idn +// - use ParseException instead of StringPrepParseException +// - change 'Normalizer.getUnicodeVersion()' to 'NormalizerImpl.getUnicodeVersion()' +// - remove all @deprecated tag to make compiler happy +// 2007-08-14 Martin Buchholz +// - remove redundant casts +// +package jdk_internal.bidi.icu.text; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import jdk_internal.bidi.Normalizer; +import jdk_internal.bidi.ParseException; +import jdk_internal.bidi.SunNormalizer; +import jdk_internal.bidi.icu.impl.CharTrie; +import jdk_internal.bidi.icu.impl.StringPrepDataReader; +import jdk_internal.bidi.icu.impl.Trie; +import jdk_internal.bidi.icu.lang.UCharacter; +import jdk_internal.bidi.icu.lang.UCharacterDirection; +import jdk_internal.bidi.icu.util.VersionInfo; + +/** + * StringPrep API implements the StingPrep framework as described by + * RFC 3454. StringPrep + * prepares Unicode strings for use in network protocols. Profiles of StingPrep + * are set of rules and data according to which the Unicode Strings are + * prepared. Each profiles contains tables which describe how a code point + * should be treated. The tables are broadly classied into + *

    + *
  • Unassigned Table: Contains code points that are unassigned in the Unicode + * Version supported by StringPrep. Currently RFC 3454 supports Unicode 3.2. + *
  • + *
  • Prohibited Table: Contains code points that are prohibted from the output + * of the StringPrep processing function.
  • + *
  • Mapping Table: Contains code ponts that are deleted from the output or + * case mapped.
  • + *
+ * + * The procedure for preparing Unicode strings: + *
    + *
  1. Map: For each character in the input, check if it has a mapping and, if + * so, replace it with its mapping.
  2. + *
  3. Normalize: Possibly normalize the result of step 1 using Unicode + * normalization.
  4. + *
  5. Prohibit: Check for any characters that are not allowed in the output. If + * any are found, return an error.
  6. + *
  7. Check bidi: Possibly check for right-to-left characters, and if any are + * found, make sure that the whole string satisfies the requirements for + * bidirectional strings. If the string does not satisfy the requirements for + * bidirectional strings, return an error.
  8. + *
+ * + * @author Ram Viswanadha + * @draft ICU 2.8 + */ +public final class StringPrep { + /** + * Option to prohibit processing of unassigned code points in the input + * + * @see #prepare + * @draft ICU 2.8 + */ + public static final int DEFAULT = 0x0000; + + /** + * Option to allow processing of unassigned code points in the input + * + * @see #prepare + * @draft ICU 2.8 + */ + public static final int ALLOW_UNASSIGNED = 0x0001; + + private static final int UNASSIGNED = 0x0000; + private static final int MAP = 0x0001; + private static final int PROHIBITED = 0x0002; + private static final int DELETE = 0x0003; + private static final int TYPE_LIMIT = 0x0004; + + private static final int NORMALIZATION_ON = 0x0001; + private static final int CHECK_BIDI_ON = 0x0002; + + private static final int TYPE_THRESHOLD = 0xFFF0; + private static final int MAX_INDEX_VALUE = 0x3FBF; /* 16139 */ + private static final int MAX_INDEX_TOP_LENGTH = 0x0003; + + /* indexes[] value names */ + private static final int INDEX_TRIE_SIZE = 0; /* number of bytes in normalization trie */ + private static final int INDEX_MAPPING_DATA_SIZE = 1; /* The array that contains the mapping */ + private static final int NORM_CORRECTNS_LAST_UNI_VERSION = 2; /* + * The index of Unicode version of last entry in + * NormalizationCorrections.txt + */ + private static final int ONE_UCHAR_MAPPING_INDEX_START = 3; /* + * The starting index of 1 UChar mapping index in the + * mapping data array + */ + private static final int TWO_UCHARS_MAPPING_INDEX_START = 4; /* + * The starting index of 2 UChars mapping index in + * the mapping data array + */ + private static final int THREE_UCHARS_MAPPING_INDEX_START = 5; + private static final int FOUR_UCHARS_MAPPING_INDEX_START = 6; + private static final int OPTIONS = 7; /* Bit set of options to turn on in the profile */ + private static final int INDEX_TOP = 16; /* changing this requires a new formatVersion */ + + /** + * Default buffer size of datafile + */ + private static final int DATA_BUFFER_SIZE = 25000; + + /* Wrappers for Trie implementations */ + private static final class StringPrepTrieImpl implements Trie.DataManipulate { + private CharTrie sprepTrie = null; + + /** + * Called by com.ibm.icu.util.Trie to extract from a lead surrogate's data the + * index array offset of the indexes for that lead surrogate. + * + * @param property data value for a surrogate from the trie, including the + * folding offset + * @return data offset or 0 if there is no data for the lead surrogate + */ + public int getFoldingOffset(int value) { + return value; + } + } + + // CharTrie implementation for reading the trie data + private StringPrepTrieImpl sprepTrieImpl; + // Indexes read from the data file + private int[] indexes; + // mapping data read from the data file + private char[] mappingData; + // format version of the data file + private byte[] formatVersion; + // the version of Unicode supported by the data file + private VersionInfo sprepUniVer; + // the Unicode version of last entry in the + // NormalizationCorrections.txt file if normalization + // is turned on + private VersionInfo normCorrVer; + // Option to turn on Normalization + private boolean doNFKC; + // Option to turn on checking for BiDi rules + private boolean checkBiDi; + + private char getCodePointValue(int ch) { + return sprepTrieImpl.sprepTrie.getCodePointValue(ch); + } + + private static VersionInfo getVersionInfo(int comp) { + int micro = comp & 0xFF; + int milli = (comp >> 8) & 0xFF; + int minor = (comp >> 16) & 0xFF; + int major = (comp >> 24) & 0xFF; + return VersionInfo.getInstance(major, minor, milli, micro); + } + + private static VersionInfo getVersionInfo(byte[] version) { + if (version.length != 4) { + return null; + } + return VersionInfo.getInstance((int) version[0], (int) version[1], (int) version[2], (int) version[3]); + } + + /** + * Creates an StringPrep object after reading the input stream. The object does + * not hold a reference to the input steam, so the stream can be closed after + * the method returns. + * + * @param inputStream The stream for reading the StringPrep profile binarySun + * @throws IOException + * @draft ICU 2.8 + */ + public StringPrep(InputStream inputStream) throws IOException { + + BufferedInputStream b = new BufferedInputStream(inputStream, DATA_BUFFER_SIZE); + + StringPrepDataReader reader = new StringPrepDataReader(b); + + // read the indexes + indexes = reader.readIndexes(INDEX_TOP); + + byte[] sprepBytes = new byte[indexes[INDEX_TRIE_SIZE]]; + + // indexes[INDEX_MAPPING_DATA_SIZE] store the size of mappingData in bytes + mappingData = new char[indexes[INDEX_MAPPING_DATA_SIZE] / 2]; + // load the rest of the data and initialize the data members + reader.read(sprepBytes, mappingData); + + sprepTrieImpl = new StringPrepTrieImpl(); + sprepTrieImpl.sprepTrie = new CharTrie(new ByteArrayInputStream(sprepBytes), sprepTrieImpl); + + // get the data format version + formatVersion = reader.getDataFormatVersion(); + + // get the options + doNFKC = ((indexes[OPTIONS] & NORMALIZATION_ON) > 0); + checkBiDi = ((indexes[OPTIONS] & CHECK_BIDI_ON) > 0); + sprepUniVer = getVersionInfo(reader.getUnicodeVersion()); + normCorrVer = getVersionInfo(indexes[NORM_CORRECTNS_LAST_UNI_VERSION]); + VersionInfo normUniVer = UCharacter.getUnicodeVersion(); + if (normUniVer.compareTo(sprepUniVer) < 0 && /* + * the Unicode version of SPREP file must be less than the + * Unicode Vesion of the normalization data + */ + normUniVer.compareTo(normCorrVer) < 0 + && /* + * the Unicode version of the NormalizationCorrections.txt file should be less + * than the Unicode Vesion of the normalization data + */ + ((indexes[OPTIONS] & NORMALIZATION_ON) > 0) /* normalization turned on */ + ) { + throw new IOException("Normalization Correction version not supported"); + } + b.close(); + } + + private static final class Values { + boolean isIndex; + int value; + int type; + + public void reset() { + isIndex = false; + value = 0; + type = -1; + } + } + + private static final void getValues(char trieWord, Values values) { + values.reset(); + if (trieWord == 0) { + /* + * Initial value stored in the mapping table just return TYPE_LIMIT .. so that + * the source codepoint is copied to the destination + */ + values.type = TYPE_LIMIT; + } else if (trieWord >= TYPE_THRESHOLD) { + values.type = (trieWord - TYPE_THRESHOLD); + } else { + /* get the type */ + values.type = MAP; + /* ascertain if the value is index or delta */ + if ((trieWord & 0x02) > 0) { + values.isIndex = true; + values.value = trieWord >> 2; // mask off the lower 2 bits and shift + + } else { + values.isIndex = false; + values.value = (trieWord << 16) >> 16; + values.value = (values.value >> 2); + + } + + if ((trieWord >> 2) == MAX_INDEX_VALUE) { + values.type = DELETE; + values.isIndex = false; + values.value = 0; + } + } + } + + private StringBuffer map(UCharacterIterator iter, int options) throws ParseException { + + Values val = new Values(); + char result = 0; + int ch = UCharacterIterator.DONE; + StringBuffer dest = new StringBuffer(); + boolean allowUnassigned = ((options & ALLOW_UNASSIGNED) > 0); + + while ((ch = iter.nextCodePoint()) != UCharacterIterator.DONE) { + + result = getCodePointValue(ch); + getValues(result, val); + + // check if the source codepoint is unassigned + if (val.type == UNASSIGNED && allowUnassigned == false) { + throw new ParseException("An unassigned code point was found in the input " + iter.getText(), + iter.getIndex()); + } else if ((val.type == MAP)) { + int index, length; + + if (val.isIndex) { + index = val.value; + if (index >= indexes[ONE_UCHAR_MAPPING_INDEX_START] + && index < indexes[TWO_UCHARS_MAPPING_INDEX_START]) { + length = 1; + } else if (index >= indexes[TWO_UCHARS_MAPPING_INDEX_START] + && index < indexes[THREE_UCHARS_MAPPING_INDEX_START]) { + length = 2; + } else if (index >= indexes[THREE_UCHARS_MAPPING_INDEX_START] + && index < indexes[FOUR_UCHARS_MAPPING_INDEX_START]) { + length = 3; + } else { + length = mappingData[index++]; + } + /* copy mapping to destination */ + dest.append(mappingData, index, length); + continue; + + } else { + ch -= val.value; + } + } else if (val.type == DELETE) { + // just consume the codepoint and contine + continue; + } + // copy the source into destination + UTF16.append(dest, ch); + } + + return dest; + } + + private StringBuffer normalize(StringBuffer src) { + /* + * Option UNORM_BEFORE_PRI_29: + * + * IDNA as interpreted by IETF members (see unicode mailing list 2004H1) + * requires strict adherence to Unicode 3.2 normalization, including buggy + * composition from before fixing Public Review Issue #29. Note that this + * results in some valid but nonsensical text to be either corrupted or + * rejected, depending on the text. See + * http://www.unicode.org/review/resolved-pri.html#pri29 See unorm.cpp and + * cnormtst.c + */ + return new StringBuffer( + SunNormalizer.normalize(src.toString(), Normalizer.Form.NFKC, SunNormalizer.UNICODE_3_2)); + } + + /* + * boolean isLabelSeparator(int ch){ int result = getCodePointValue(ch); if( + * (result & 0x07) == LABEL_SEPARATOR){ return true; } return false; } + */ + /* + * 1) Map -- For each character in the input, check if it has a mapping and, if + * so, replace it with its mapping. + * + * 2) Normalize -- Possibly normalize the result of step 1 using Unicode + * normalization. + * + * 3) Prohibit -- Check for any characters that are not allowed in the output. + * If any are found, return an error. + * + * 4) Check bidi -- Possibly check for right-to-left characters, and if any are + * found, make sure that the whole string satisfies the requirements for + * bidirectional strings. If the string does not satisfy the requirements for + * bidirectional strings, return an error. [Unicode3.2] defines several + * bidirectional categories; each character has one bidirectional category + * assigned to it. For the purposes of the requirements below, an + * "RandALCat character" is a character that has Unicode bidirectional + * categories "R" or "AL"; an "LCat character" is a character that has Unicode + * bidirectional category "L". Note + * + * + * that there are many characters which fall in neither of the above + * definitions; Latin digits ( through ) are examples of this + * because they have bidirectional category "EN". + * + * In any profile that specifies bidirectional character handling, all three of + * the following requirements MUST be met: + * + * 1) The characters in section 5.8 MUST be prohibited. + * + * 2) If a string contains any RandALCat character, the string MUST NOT contain + * any LCat character. + * + * 3) If a string contains any RandALCat character, a RandALCat character MUST + * be the first character of the string, and a RandALCat character MUST be the + * last character of the string. + */ + /** + * Prepare the input buffer for use in applications with the given profile. This + * operation maps, normalizes(NFKC), checks for prohited and BiDi characters in + * the order defined by RFC 3454 depending on the options specified in the + * profile. + * + * @param src A UCharacterIterator object containing the source string + * @param options A bit set of options: + * + * - StringPrep.NONE Prohibit processing of unassigned code + * points in the input + * + * - StringPrep.ALLOW_UNASSIGNED Treat the unassigned code points + * are in the input as normal Unicode code points. + * + * @return StringBuffer A StringBuffer containing the output + * @throws ParseException + * @draft ICU 2.8 + */ + public StringBuffer prepare(UCharacterIterator src, int options) throws ParseException { + + // map + StringBuffer mapOut = map(src, options); + StringBuffer normOut = mapOut;// initialize + + if (doNFKC) { + // normalize + normOut = normalize(mapOut); + } + + int ch; + char result; + UCharacterIterator iter = UCharacterIterator.getInstance(normOut); + Values val = new Values(); + int direction = UCharacterDirection.CHAR_DIRECTION_COUNT, + firstCharDir = UCharacterDirection.CHAR_DIRECTION_COUNT; + int rtlPos = -1, ltrPos = -1; + boolean rightToLeft = false, leftToRight = false; + + while ((ch = iter.nextCodePoint()) != UCharacterIterator.DONE) { + result = getCodePointValue(ch); + getValues(result, val); + + if (val.type == PROHIBITED) { + throw new ParseException("A prohibited code point was found in the input" + iter.getText(), val.value); + } + + direction = UCharacter.getDirection(ch); + if (firstCharDir == UCharacterDirection.CHAR_DIRECTION_COUNT) { + firstCharDir = direction; + } + if (direction == UCharacterDirection.LEFT_TO_RIGHT) { + leftToRight = true; + ltrPos = iter.getIndex() - 1; + } + if (direction == UCharacterDirection.RIGHT_TO_LEFT + || direction == UCharacterDirection.RIGHT_TO_LEFT_ARABIC) { + rightToLeft = true; + rtlPos = iter.getIndex() - 1; + } + } + if (checkBiDi == true) { + // satisfy 2 + if (leftToRight == true && rightToLeft == true) { + throw new ParseException( + "The input does not conform to the rules for BiDi code points." + iter.getText(), + (rtlPos > ltrPos) ? rtlPos : ltrPos); + } + + // satisfy 3 + if (rightToLeft == true && !((firstCharDir == UCharacterDirection.RIGHT_TO_LEFT + || firstCharDir == UCharacterDirection.RIGHT_TO_LEFT_ARABIC) + && (direction == UCharacterDirection.RIGHT_TO_LEFT + || direction == UCharacterDirection.RIGHT_TO_LEFT_ARABIC))) { + throw new ParseException( + "The input does not conform to the rules for BiDi code points." + iter.getText(), + (rtlPos > ltrPos) ? rtlPos : ltrPos); + } + } + return normOut; + + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/UCharacterIterator.java b/src/main/java/jdk_internal/bidi/icu/text/UCharacterIterator.java new file mode 100755 index 00000000..656b4df5 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/UCharacterIterator.java @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 1996-2014, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.text; + +import jdk_internal.bidi.CharacterIterator; +import jdk_internal.bidi.icu.impl.CharacterIteratorWrapper; +import jdk_internal.bidi.icu.impl.ReplaceableUCharacterIterator; +import jdk_internal.bidi.icu.impl.UCharacterProperty; + +/** + * Abstract class that defines an API for iteration on text objects.This is an + * interface for forward and backward iteration and random access into a text + * object. Forward iteration is done with post-increment and backward iteration + * is done with pre-decrement semantics, while the + * java.text.CharacterIterator interface methods provided forward + * iteration with "pre-increment" and backward iteration with pre-decrement + * semantics. This API is more efficient for forward iteration over code points. + * The other major difference is that this API can do both code unit and code + * point iteration, java.text.CharacterIterator can only iterate + * over code units and is limited to BMP (0 - 0xFFFF) + * + * @author Ram + * @stable ICU 2.4 + */ +public abstract class UCharacterIterator implements Cloneable { + + /** + * Protected default constructor for the subclasses + * + * @stable ICU 2.4 + */ + protected UCharacterIterator() { + } + + /** + * Indicator that we have reached the ends of the UTF16 text. Moved from + * UForwardCharacterIterator.java + * + * @stable ICU 2.4 + */ + public static final int DONE = -1; + + // static final methods ---------------------------------------------------- + + /** + * Returns a UCharacterIterator object given a source string. + * + * @param source a string + * @return UCharacterIterator object + * @exception IllegalArgumentException if the argument is null + * @stable ICU 2.4 + */ + public static final UCharacterIterator getInstance(String source) { + return new ReplaceableUCharacterIterator(source); + } + + /** + * Returns a UCharacterIterator object given a source StringBuffer. + * + * @param source an string buffer of UTF-16 code units + * @return UCharacterIterator object + * @exception IllegalArgumentException if the argument is null + * @stable ICU 2.4 + */ + public static final UCharacterIterator getInstance(StringBuffer source) { + return new ReplaceableUCharacterIterator(source); + } + + /** + * Returns a UCharacterIterator object given a CharacterIterator. + * + * @param source a valid CharacterIterator object. + * @return UCharacterIterator object + * @exception IllegalArgumentException if the argument is null + * @stable ICU 2.4 + */ + public static final UCharacterIterator getInstance(CharacterIterator source) { + return new CharacterIteratorWrapper(source); + } + + // public methods ---------------------------------------------------------- + + /** + * Returns the length of the text + * + * @return length of the text + * @stable ICU 2.4 + */ + public abstract int getLength(); + + /** + * Gets the current index in text. + * + * @return current index in text. + * @stable ICU 2.4 + */ + public abstract int getIndex(); + + /** + * Returns the UTF16 code unit at index, and increments to the next code unit + * (post-increment semantics). If index is out of range, DONE is returned, and + * the iterator is reset to the limit of the text. + * + * @return the next UTF16 code unit, or DONE if the index is at the limit of the + * text. + * @stable ICU 2.4 + */ + public abstract int next(); + + /** + * Returns the code point at index, and increments to the next code point + * (post-increment semantics). If index does not point to a valid surrogate + * pair, the behavior is the same as next(). Otherwise the iterator + * is incremented past the surrogate pair, and the code point represented by the + * pair is returned. + * + * @return the next codepoint in text, or DONE if the index is at the limit of + * the text. + * @stable ICU 2.4 + */ + public int nextCodePoint() { + int ch1 = next(); + if (UTF16.isLeadSurrogate((char) ch1)) { + int ch2 = next(); + if (UTF16.isTrailSurrogate((char) ch2)) { + return UCharacterProperty.getRawSupplementary((char) ch1, (char) ch2); + } else if (ch2 != DONE) { + // unmatched surrogate so back out + previous(); + } + } + return ch1; + } + + /** + * Decrement to the position of the previous code unit in the text, and return + * it (pre-decrement semantics). If the resulting index is less than 0, the + * index is reset to 0 and DONE is returned. + * + * @return the previous code unit in the text, or DONE if the new index is + * before the start of the text. + * @stable ICU 2.4 + */ + public abstract int previous(); + + /** + * Retreat to the start of the previous code point in the text, and return it + * (pre-decrement semantics). If the index is not preceeded by a valid surrogate + * pair, the behavior is the same as previous(). Otherwise the + * iterator is decremented to the start of the surrogate pair, and the code + * point represented by the pair is returned. + * + * @return the previous code point in the text, or DONE if the new index is + * before the start of the text. + * @stable ICU 2.4 + */ + public int previousCodePoint() { + int ch1 = previous(); + if (UTF16.isTrailSurrogate((char) ch1)) { + int ch2 = previous(); + if (UTF16.isLeadSurrogate((char) ch2)) { + return UCharacterProperty.getRawSupplementary((char) ch2, (char) ch1); + } else if (ch2 != DONE) { + // unmatched trail surrogate so back out + next(); + } + } + return ch1; + } + + /** + * Sets the index to the specified index in the text. + * + * @param index the index within the text. + * @exception IndexOutOfBoundsException is thrown if an invalid index is + * supplied + * @stable ICU 2.4 + */ + public abstract void setIndex(int index); + + /** + * Sets the current index to the start. + * + * @stable ICU 2.4 + */ + public void setToStart() { + setIndex(0); + } + + /** + * Fills the buffer with the underlying text storage of the iterator If the + * buffer capacity is not enough a exception is thrown. The capacity of the fill + * in buffer should at least be equal to length of text in the iterator obtained + * by calling getLength(). Usage: + * + *
{@code
+	 *         UChacterIterator iter = new UCharacterIterator.getInstance(text);
+	 *         char[] buf = new char[iter.getLength()];
+	 *         iter.getText(buf);
+	 *
+	 *         OR
+	 *         char[] buf= new char[1];
+	 *         int len = 0;
+	 *         for(;;){
+	 *             try{
+	 *                 len = iter.getText(buf);
+	 *                 break;
+	 *             }catch(IndexOutOfBoundsException e){
+	 *                 buf = new char[iter.getLength()];
+	 *             }
+	 *         }
+	 * }
+ * + * @param fillIn an array of chars to fill with the underlying UTF-16 code + * units. + * @param offset the position within the array to start putting the data. + * @return the number of code units added to fillIn, as a convenience + * @exception IndexOutOfBoundsException exception if there is not enough room + * after offset in the array, or if offset + * < 0. + * @stable ICU 2.4 + */ + public abstract int getText(char[] fillIn, int offset); + + /** + * Convenience override for getText(char[], int) that provides an + * offset of 0. + * + * @param fillIn an array of chars to fill with the underlying UTF-16 code + * units. + * @return the number of code units added to fillIn, as a convenience + * @exception IndexOutOfBoundsException exception if there is not enough room in + * the array. + * @stable ICU 2.4 + */ + public final int getText(char[] fillIn) { + return getText(fillIn, 0); + } + + /** + * Convenience method for returning the underlying text storage as a string + * + * @return the underlying text storage in the iterator as a string + * @stable ICU 2.4 + */ + public String getText() { + char[] text = new char[getLength()]; + getText(text); + return new String(text); + } + + /** + * Moves the current position by the number of code points specified, either + * forward or backward depending on the sign of delta (positive or negative + * respectively). If the current index is at a trail surrogate then the first + * adjustment is by code unit, and the remaining adjustments are by code points. + * If the resulting index would be less than zero, the index is set to zero, and + * if the resulting index would be greater than limit, the index is set to + * limit. + * + * @param delta the number of code units to move the current index. + * @return the new index + * @exception IndexOutOfBoundsException is thrown if an invalid delta is + * supplied + * @stable ICU 2.4 + * + */ + public int moveCodePointIndex(int delta) { + if (delta > 0) { + while (delta > 0 && nextCodePoint() != DONE) { + delta--; + } + } else { + while (delta < 0 && previousCodePoint() != DONE) { + delta++; + } + } + if (delta != 0) { + throw new IndexOutOfBoundsException(); + } + + return getIndex(); + } + + /** + * Creates a copy of this iterator, independent from other iterators. If it is + * not possible to clone the iterator, returns null. + * + * @return copy of this iterator + * @stable ICU 2.4 + */ + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/UTF16.java b/src/main/java/jdk_internal/bidi/icu/text/UTF16.java new file mode 100755 index 00000000..5a39fedf --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/UTF16.java @@ -0,0 +1,609 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/** + ******************************************************************************* + * Copyright (C) 1996-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.text; + +import jdk_internal.bidi.icu.impl.UCharacterProperty; + +/** + *

+ * Standalone utility class providing UTF16 character conversions and indexing + * conversions. + *

+ * Code that uses strings alone rarely need modification. By design, UTF-16 does + * not allow overlap, so searching for strings is a safe operation. Similarly, + * concatenation is always safe. Substringing is safe if the start and end are + * both on UTF-32 boundaries. In normal code, the values for start and end are + * on those boundaries, since they arose from operations like searching. If not, + * the nearest UTF-32 boundaries can be determined using bounds(). + * Examples: + *

+ * The following examples illustrate use of some of these methods. + * + *

{@code
+ * // iteration forwards: Original
+ * for (int i = 0; i < s.length(); ++i) {
+ * 	char ch = s.charAt(i);
+ * 	doSomethingWith(ch);
+ * }
+ *
+ * // iteration forwards: Changes for UTF-32
+ * int ch;
+ * for (int i = 0; i < s.length(); i += UTF16.getCharCount(ch)) {
+ * 	ch = UTF16.charAt(s, i);
+ * 	doSomethingWith(ch);
+ * }
+ *
+ * // iteration backwards: Original
+ * for (int i = s.length() - 1; i >= 0; --i) {
+ * 	char ch = s.charAt(i);
+ * 	doSomethingWith(ch);
+ * }
+ *
+ * // iteration backwards: Changes for UTF-32
+ * int ch;
+ * for (int i = s.length() - 1; i > 0; i -= UTF16.getCharCount(ch)) {
+ * 	ch = UTF16.charAt(s, i);
+ * 	doSomethingWith(ch);
+ * }
+ * }
+ * + * Notes: + *
    + *
  • Naming: For clarity, High and Low surrogates are called + * Lead and Trail in the API, which gives a better + * sense of their ordering in a string. offset16 and + * offset32 are used to distinguish offsets to UTF-16 boundaries vs + * offsets to UTF-32 boundaries. int char32 is used to contain + * UTF-32 characters, as opposed to char16, which is a UTF-16 code + * unit.
  • + *
  • Roundtripping Offsets: You can always roundtrip from a + * UTF-32 offset to a UTF-16 offset and back. Because of the difference in + * structure, you can roundtrip from a UTF-16 offset to a UTF-32 offset and back + * if and only if bounds(string, offset16) != TRAIL.
  • + *
  • Exceptions: The error checking will throw an exception + * if indices are out of bounds. Other than that, all methods will behave + * reasonably, even if unmatched surrogates or out-of-bounds UTF-32 values are + * present. UCharacter.isLegal() can be used to check for validity + * if desired.
  • + *
  • Unmatched Surrogates: If the string contains unmatched + * surrogates, then these are counted as one UTF-32 value. This matches their + * iteration behavior, which is vital. It also matches common display practice + * as missing glyphs (see the Unicode Standard Section 5.4, 5.5).
  • + *
  • Optimization: The method implementations may need + * optimization if the compiler doesn't fold static final methods. Since + * surrogate pairs will form an exceeding small percentage of all the text in + * the world, the singleton case should always be optimized for.
  • + *
+ * + * @author Mark Davis, with help from Markus Scherer + * @stable ICU 2.1 + */ + +public final class UTF16 { + // public variables --------------------------------------------------- + + /** + * The lowest Unicode code point value. + * + * @stable ICU 2.1 + */ + public static final int CODEPOINT_MIN_VALUE = 0; + /** + * The highest Unicode code point value (scalar value) according to the Unicode + * Standard. + * + * @stable ICU 2.1 + */ + public static final int CODEPOINT_MAX_VALUE = 0x10ffff; + /** + * The minimum value for Supplementary code points + * + * @stable ICU 2.1 + */ + public static final int SUPPLEMENTARY_MIN_VALUE = 0x10000; + /** + * Lead surrogate minimum value + * + * @stable ICU 2.1 + */ + public static final int LEAD_SURROGATE_MIN_VALUE = 0xD800; + /** + * Trail surrogate minimum value + * + * @stable ICU 2.1 + */ + public static final int TRAIL_SURROGATE_MIN_VALUE = 0xDC00; + /** + * Lead surrogate maximum value + * + * @stable ICU 2.1 + */ + public static final int LEAD_SURROGATE_MAX_VALUE = 0xDBFF; + /** + * Trail surrogate maximum value + * + * @stable ICU 2.1 + */ + public static final int TRAIL_SURROGATE_MAX_VALUE = 0xDFFF; + /** + * Surrogate minimum value + * + * @stable ICU 2.1 + */ + public static final int SURROGATE_MIN_VALUE = LEAD_SURROGATE_MIN_VALUE; + /** + * Lead surrogate bitmask + */ + private static final int LEAD_SURROGATE_BITMASK = 0xFFFFFC00; + /** + * Trail surrogate bitmask + */ + private static final int TRAIL_SURROGATE_BITMASK = 0xFFFFFC00; + /** + * Surrogate bitmask + */ + private static final int SURROGATE_BITMASK = 0xFFFFF800; + /** + * Lead surrogate bits + */ + private static final int LEAD_SURROGATE_BITS = 0xD800; + /** + * Trail surrogate bits + */ + private static final int TRAIL_SURROGATE_BITS = 0xDC00; + /** + * Surrogate bits + */ + private static final int SURROGATE_BITS = 0xD800; + + // constructor -------------------------------------------------------- + + // /CLOVER:OFF + /** + * Prevent instance from being created. + */ + private UTF16() { + } + + // /CLOVER:ON + // public method ------------------------------------------------------ + + /** + * Extract a single UTF-32 value from a string. Used when iterating forwards or + * backwards (with UTF16.getCharCount(), as well as random access. + * If a validity check is required, use + * + * UCharacter.isLegal() on the return value. If the char retrieved is + * part of a surrogate pair, its supplementary character will be returned. If a + * complete supplementary character is not found the incomplete character will + * be returned + * + * @param source array of UTF-16 chars + * @param offset16 UTF-16 offset to the start of the character. + * @return UTF-32 value for the UTF-32 value that contains the char at offset16. + * The boundaries of that codepoint are the same as in + * bounds32(). + * @exception IndexOutOfBoundsException thrown if offset16 is out of bounds. + * @stable ICU 2.1 + */ + public static int charAt(String source, int offset16) { + char single = source.charAt(offset16); + if (single < LEAD_SURROGATE_MIN_VALUE) { + return single; + } + return _charAt(source, offset16, single); + } + + private static int _charAt(String source, int offset16, char single) { + if (single > TRAIL_SURROGATE_MAX_VALUE) { + return single; + } + + // Convert the UTF-16 surrogate pair if necessary. + // For simplicity in usage, and because the frequency of pairs is + // low, look both directions. + + if (single <= LEAD_SURROGATE_MAX_VALUE) { + ++offset16; + if (source.length() != offset16) { + char trail = source.charAt(offset16); + if (trail >= TRAIL_SURROGATE_MIN_VALUE && trail <= TRAIL_SURROGATE_MAX_VALUE) { + return UCharacterProperty.getRawSupplementary(single, trail); + } + } + } else { + --offset16; + if (offset16 >= 0) { + // single is a trail surrogate so + char lead = source.charAt(offset16); + if (lead >= LEAD_SURROGATE_MIN_VALUE && lead <= LEAD_SURROGATE_MAX_VALUE) { + return UCharacterProperty.getRawSupplementary(lead, single); + } + } + } + return single; // return unmatched surrogate + } + + /** + * Extract a single UTF-32 value from a string. Used when iterating forwards or + * backwards (with UTF16.getCharCount(), as well as random access. + * If a validity check is required, use + * UCharacter.isLegal() + * on the return value. If the char retrieved is part of a surrogate + * pair, its supplementary character will be returned. If a complete + * supplementary character is not found the incomplete character will be + * returned + * + * @param source array of UTF-16 chars + * @param offset16 UTF-16 offset to the start of the character. + * @return UTF-32 value for the UTF-32 value that contains the char at offset16. + * The boundaries of that codepoint are the same as in + * bounds32(). + * @exception IndexOutOfBoundsException thrown if offset16 is out of bounds. + * @stable ICU 2.1 + */ + public static int charAt(CharSequence source, int offset16) { + char single = source.charAt(offset16); + if (single < UTF16.LEAD_SURROGATE_MIN_VALUE) { + return single; + } + return _charAt(source, offset16, single); + } + + private static int _charAt(CharSequence source, int offset16, char single) { + if (single > UTF16.TRAIL_SURROGATE_MAX_VALUE) { + return single; + } + + // Convert the UTF-16 surrogate pair if necessary. + // For simplicity in usage, and because the frequency of pairs is + // low, look both directions. + + if (single <= UTF16.LEAD_SURROGATE_MAX_VALUE) { + ++offset16; + if (source.length() != offset16) { + char trail = source.charAt(offset16); + if (trail >= UTF16.TRAIL_SURROGATE_MIN_VALUE && trail <= UTF16.TRAIL_SURROGATE_MAX_VALUE) { + return UCharacterProperty.getRawSupplementary(single, trail); + } + } + } else { + --offset16; + if (offset16 >= 0) { + // single is a trail surrogate so + char lead = source.charAt(offset16); + if (lead >= UTF16.LEAD_SURROGATE_MIN_VALUE && lead <= UTF16.LEAD_SURROGATE_MAX_VALUE) { + return UCharacterProperty.getRawSupplementary(lead, single); + } + } + } + return single; // return unmatched surrogate + } + + /** + * Extract a single UTF-32 value from a substring. Used when iterating forwards + * or backwards (with UTF16.getCharCount(), as well as random + * access. If a validity check is required, use + * UCharacter.isLegal() + * on the return value. If the char retrieved is part of a surrogate + * pair, its supplementary character will be returned. If a complete + * supplementary character is not found the incomplete character will be + * returned + * + * @param source Array of UTF-16 chars + * @param start Offset to substring in the source array for analyzing + * @param limit Offset to substring in the source array for analyzing + * @param offset16 UTF-16 offset relative to start + * @return UTF-32 value for the UTF-32 value that contains the char at offset16. + * The boundaries of that codepoint are the same as in + * bounds32(). + * @exception IndexOutOfBoundsException Thrown if offset16 is not within the + * range of start and limit. + * @stable ICU 2.1 + */ + public static int charAt(char source[], int start, int limit, int offset16) { + offset16 += start; + if (offset16 < start || offset16 >= limit) { + throw new ArrayIndexOutOfBoundsException(offset16); + } + + char single = source[offset16]; + if (!isSurrogate(single)) { + return single; + } + + // Convert the UTF-16 surrogate pair if necessary. + // For simplicity in usage, and because the frequency of pairs is + // low, look both directions. + if (single <= LEAD_SURROGATE_MAX_VALUE) { + offset16++; + if (offset16 >= limit) { + return single; + } + char trail = source[offset16]; + if (isTrailSurrogate(trail)) { + return UCharacterProperty.getRawSupplementary(single, trail); + } + } else { // isTrailSurrogate(single), so + if (offset16 == start) { + return single; + } + offset16--; + char lead = source[offset16]; + if (isLeadSurrogate(lead)) + return UCharacterProperty.getRawSupplementary(lead, single); + } + return single; // return unmatched surrogate + } + + /** + * Determines how many chars this char32 requires. If a validity check is + * required, use + * isLegal() on + * char32 before calling. + * + * @param char32 the input codepoint. + * @return 2 if is in supplementary space, otherwise 1. + * @stable ICU 2.1 + */ + public static int getCharCount(int char32) { + if (char32 < SUPPLEMENTARY_MIN_VALUE) { + return 1; + } + return 2; + } + + /** + * Determines whether the code value is a surrogate. + * + * @param char16 the input character. + * @return true if the input character is a surrogate. + * @stable ICU 2.1 + */ + public static boolean isSurrogate(char char16) { + return (char16 & SURROGATE_BITMASK) == SURROGATE_BITS; + } + + /** + * Determines whether the character is a trail surrogate. + * + * @param char16 the input character. + * @return true if the input character is a trail surrogate. + * @stable ICU 2.1 + */ + public static boolean isTrailSurrogate(char char16) { + return (char16 & TRAIL_SURROGATE_BITMASK) == TRAIL_SURROGATE_BITS; + } + + /** + * Determines whether the character is a lead surrogate. + * + * @param char16 the input character. + * @return true if the input character is a lead surrogate + * @stable ICU 2.1 + */ + public static boolean isLeadSurrogate(char char16) { + return (char16 & LEAD_SURROGATE_BITMASK) == LEAD_SURROGATE_BITS; + } + + /** + * Returns the lead surrogate. If a validity check is required, use + * isLegal() on + * char32 before calling. + * + * @param char32 the input character. + * @return lead surrogate if the getCharCount(ch) is 2;
+ * and 0 otherwise (note: 0 is not a valid lead surrogate). + * @stable ICU 2.1 + */ + public static char getLeadSurrogate(int char32) { + if (char32 >= SUPPLEMENTARY_MIN_VALUE) { + return (char) (LEAD_SURROGATE_OFFSET_ + (char32 >> LEAD_SURROGATE_SHIFT_)); + } + + return 0; + } + + /** + * Returns the trail surrogate. If a validity check is required, use + * isLegal() on + * char32 before calling. + * + * @param char32 the input character. + * @return the trail surrogate if the getCharCount(ch) is 2;
+ * otherwise the character itself + * @stable ICU 2.1 + */ + public static char getTrailSurrogate(int char32) { + if (char32 >= SUPPLEMENTARY_MIN_VALUE) { + return (char) (TRAIL_SURROGATE_MIN_VALUE + (char32 & TRAIL_SURROGATE_MASK_)); + } + + return (char) char32; + } + + /** + * Convenience method corresponding to String.valueOf(char). Returns a one or + * two char string containing the UTF-32 value in UTF16 format. If a validity + * check is required, use + * isLegal() on + * char32 before calling. + * + * @param char32 the input character. + * @return string value of char32 in UTF16 format + * @exception IllegalArgumentException thrown if char32 is a invalid codepoint. + * @stable ICU 2.1 + */ + public static String valueOf(int char32) { + if (char32 < CODEPOINT_MIN_VALUE || char32 > CODEPOINT_MAX_VALUE) { + throw new IllegalArgumentException("Illegal codepoint"); + } + return toString(char32); + } + + /** + * Append a single UTF-32 value to the end of a StringBuffer. If a validity + * check is required, use + * isLegal() on + * char32 before calling. + * + * @param target the buffer to append to + * @param char32 value to append. + * @return the updated StringBuffer + * @exception IllegalArgumentException thrown when char32 does not lie within + * the range of the Unicode codepoints + * @stable ICU 2.1 + */ + public static StringBuffer append(StringBuffer target, int char32) { + // Check for irregular values + if (char32 < CODEPOINT_MIN_VALUE || char32 > CODEPOINT_MAX_VALUE) { + throw new IllegalArgumentException("Illegal codepoint: " + Integer.toHexString(char32)); + } + + // Write the UTF-16 values + if (char32 >= SUPPLEMENTARY_MIN_VALUE) { + target.append(getLeadSurrogate(char32)); + target.append(getTrailSurrogate(char32)); + } else { + target.append((char) char32); + } + return target; + } + + /** + * Shifts offset16 by the argument number of codepoints within a subarray. + * + * @param source char array + * @param start position of the subarray to be performed on + * @param limit position of the subarray to be performed on + * @param offset16 UTF16 position to shift relative to start + * @param shift32 number of codepoints to shift + * @return new shifted offset16 relative to start + * @exception IndexOutOfBoundsException if the new offset16 is out of bounds + * with respect to the subarray or the + * subarray bounds are out of range. + * @stable ICU 2.1 + */ + public static int moveCodePointOffset(char source[], int start, int limit, int offset16, int shift32) { + int size = source.length; + int count; + char ch; + int result = offset16 + start; + if (start < 0 || limit < start) { + throw new StringIndexOutOfBoundsException(start); + } + if (limit > size) { + throw new StringIndexOutOfBoundsException(limit); + } + if (offset16 < 0 || result > limit) { + throw new StringIndexOutOfBoundsException(offset16); + } + if (shift32 > 0) { + if (shift32 + result > size) { + throw new StringIndexOutOfBoundsException(result); + } + count = shift32; + while (result < limit && count > 0) { + ch = source[result]; + if (isLeadSurrogate(ch) && (result + 1 < limit) && isTrailSurrogate(source[result + 1])) { + result++; + } + count--; + result++; + } + } else { + if (result + shift32 < start) { + throw new StringIndexOutOfBoundsException(result); + } + for (count = -shift32; count > 0; count--) { + result--; + if (result < start) { + break; + } + ch = source[result]; + if (isTrailSurrogate(ch) && result > start && isLeadSurrogate(source[result - 1])) { + result--; + } + } + } + if (count != 0) { + throw new StringIndexOutOfBoundsException(shift32); + } + result -= start; + return result; + } + + // private data members ------------------------------------------------- + + /** + * Shift value for lead surrogate to form a supplementary character. + */ + private static final int LEAD_SURROGATE_SHIFT_ = 10; + + /** + * Mask to retrieve the significant value from a trail surrogate. + */ + private static final int TRAIL_SURROGATE_MASK_ = 0x3FF; + + /** + * Value that all lead surrogate starts with + */ + private static final int LEAD_SURROGATE_OFFSET_ = LEAD_SURROGATE_MIN_VALUE + - (SUPPLEMENTARY_MIN_VALUE >> LEAD_SURROGATE_SHIFT_); + + // private methods ------------------------------------------------------ + + /** + *

+ * Converts argument code point and returns a String object representing the + * code point's value in UTF16 format. + *

+ * This method does not check for the validity of the codepoint, the results are + * not guaranteed if a invalid codepoint is passed as argument. + *

+ * The result is a string whose length is 1 for non-supplementary code points, 2 + * otherwise. + * + * @param ch code point + * @return string representation of the code point + */ + private static String toString(int ch) { + if (ch < SUPPLEMENTARY_MIN_VALUE) { + return String.valueOf((char) ch); + } + + StringBuilder result = new StringBuilder(); + result.append(getLeadSurrogate(ch)); + result.append(getTrailSurrogate(ch)); + return result.toString(); + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/UnicodeSet.java b/src/main/java/jdk_internal/bidi/icu/text/UnicodeSet.java new file mode 100755 index 00000000..5797c6be --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/UnicodeSet.java @@ -0,0 +1,1515 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 1996-2015, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ +package jdk_internal.bidi.icu.text; + +import java.text.ParsePosition; +import java.util.ArrayList; +import java.util.TreeSet; + +import jdk_internal.bidi.icu.impl.BMPSet; +import jdk_internal.bidi.icu.impl.UCharacterProperty; +import jdk_internal.bidi.icu.impl.UnicodeSetStringSpan; +import jdk_internal.bidi.icu.impl.Utility; +import jdk_internal.bidi.icu.lang.UCharacter; +import jdk_internal.bidi.icu.util.OutputInt; +import jdk_internal.bidi.icu.util.VersionInfo; + +/** + * A mutable set of Unicode characters and multicharacter strings. Objects of + * this class represent character classes used in regular expressions. + * A character specifies a subset of Unicode code points. Legal code points are + * U+0000 to U+10FFFF, inclusive. + * + * Note: method freeze() will not only make the set immutable, but also makes + * important methods much higher performance: contains(c), containsNone(...), + * span(...), spanBack(...) etc. After the object is frozen, any subsequent call + * that wants to change the object will throw UnsupportedOperationException. + * + *

+ * The UnicodeSet class is not designed to be subclassed. + * + *

+ * UnicodeSet supports two APIs. The first is the operand + * API that allows the caller to modify the value of a UnicodeSet + * object. It conforms to Java 2's java.util.Set interface, + * although UnicodeSet does not actually implement that interface. + * All methods of Set are supported, with the modification that + * they take a character range or single character instead of an + * Object, and they take a UnicodeSet instead of a + * Collection. The operand API may be thought of in terms of + * boolean logic: a boolean OR is implemented by add, a boolean AND + * is implemented by retain, a boolean XOR is implemented by + * complement taking an argument, and a boolean NOT is implemented + * by complement with no argument. In terms of traditional set + * theory function names, add is a union, retain is an + * intersection, remove is an asymmetric difference, and + * complement with no argument is a set complement with respect to + * the superset range MIN_VALUE-MAX_VALUE + * + *

+ * The second API is the applyPattern()/toPattern() + * API from the java.text.Format-derived classes. Unlike the + * methods that add characters, add categories, and control the logic of the + * set, the method applyPattern() sets all attributes of a + * UnicodeSet at once, based on a string pattern. + * + *

+ * Pattern syntax + *

+ * + * Patterns are accepted by the constructors and the applyPattern() + * methods and returned by the toPattern() method. These patterns + * follow a syntax similar to that employed by version 8 regular expression + * character classes. Here are some simple examples: + * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
[]No characters
[a]The character 'a'
[ae]The characters 'a' and 'e'
[a-e]The characters 'a' through 'e' inclusive, in Unicode code + * point order
[\\u4E01]The character U+4E01
[a{ab}{ac}]The character 'a' and the multicharacter strings "ab" and + * "ac"
[\p{Lu}]All characters in the general category Uppercase Letter
+ *
+ * + * Any character may be preceded by a backslash in order to remove any special + * meaning. White space characters, as defined by the Unicode + * Pattern_White_Space property, are ignored, unless they are escaped. + * + *

+ * Property patterns specify a set of characters having a certain property as + * defined by the Unicode standard. Both the POSIX-like "[:Lu:]" and the + * Perl-like syntax "\p{Lu}" are recognized. For a complete list of supported + * property patterns, see the User's Guide for UnicodeSet at + * + * http://www.icu-project.org/userguide/unicodeSet.html. Actual + * determination of property data is defined by the underlying Unicode database + * as implemented by UCharacter. + * + *

+ * Patterns specify individual characters, ranges of characters, and Unicode + * property sets. When elements are concatenated, they specify their union. To + * complement a set, place a '^' immediately after the opening '['. Property + * patterns are inverted by modifying their delimiters; "[:^foo]" and "\P{foo}". + * In any other location, '^' has no special meaning. + * + *

+ * Ranges are indicated by placing two a '-' between two characters, as in + * "a-z". This specifies the range of all characters from the left to the right, + * in Unicode order. If the left character is greater than or equal to the right + * character it is a syntax error. If a '-' occurs as the first character after + * the opening '[' or '[^', or if it occurs as the last character before the + * closing ']', then it is taken as a literal. Thus "[a\\-b]", "[-ab]", and + * "[ab-]" all indicate the same set of three characters, 'a', 'b', and '-'. + * + *

+ * Sets may be intersected using the {@literal '&'} operator or the asymmetric + * set difference may be taken using the '-' operator, for example, + * "{@code [[:L:]&[\\u0000-\\u0FFF]]}" indicates the set of all Unicode letters + * with values less than 4096. Operators ({@literal '&'} and '|') have equal + * precedence and bind left-to-right. Thus "[[:L:]-[a-z]-[\\u0100-\\u01FF]]" is + * equivalent to "[[[:L:]-[a-z]]-[\\u0100-\\u01FF]]". This only really matters + * for difference; intersection is commutative. + * + * + * + * + * + * + * + * + * + * + *
[a] + * The set containing 'a' + *
[a-z] + * The set containing 'a' through 'z' and all letters in between, in Unicode + * order + *
[^a-z] + * The set containing all characters but 'a' through 'z', that is, U+0000 + * through 'a'-1 and 'z'+1 through U+10FFFF + *
[[pat1][pat2]] + * The union of sets specified by pat1 and pat2 + *
[[pat1]&[pat2]] + * The intersection of sets specified by pat1 and pat2 + *
[[pat1]-[pat2]] + * The asymmetric difference of sets specified by pat1 and + * pat2 + *
[:Lu:] or \p{Lu} + * The set of characters having the specified Unicode property; in this + * case, Unicode uppercase letters + *
[:^Lu:] or \P{Lu} + * The set of characters not having the given Unicode property + *
+ * + *

+ * Warning: you cannot add an empty string ("") to a UnicodeSet. + *

+ * + *

+ * Formal syntax + *

+ * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
pattern :=  ('[' '^'? item* ']') | + * property
item :=  char | (char '-' char) | pattern-expr
+ *
pattern-expr :=  pattern | pattern-expr pattern | + * pattern-expr op pattern
+ *
op :=  '&' | '-'
+ *
special :=  '[' | ']' | '-'
+ *
char :=  any character that is not special
+ * | ('\\'
any character)
+ * | ('\u' hex hex hex hex)
+ *
hex :=  any character for which + * Character.digit(c, 16) returns a non-negative + * result
property :=  a Unicode property set pattern
+ *
+ * + * + * + * + *
Legend: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
a := b a may be replaced by b
a?zero or one instance of a
+ *
a*one or more instances of a
+ *
a | beither a or b
+ *
'a'the literal string between the quotes
+ *
+ *
+ *

+ * To iterate over contents of UnicodeSet, the following are available: + *

    + *
  • {@link #ranges()} to iterate through the ranges
  • + *
  • {@link #strings()} to iterate through the strings
  • + *
  • {@link #iterator()} to iterate through the entire contents in a single + * loop. That method is, however, not particularly efficient, since it "boxes" + * each code point into a String. + *
+ * All of the above can be used in for loops. The + * {@link com.ibm.icu.text.UnicodeSetIterator UnicodeSetIterator} can also be + * used, but not in for loops. + *

+ * To replace, count elements, or delete spans, see + * {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * + * @author Alan Liu + * @stable ICU 2.0 + */ +public class UnicodeSet { + + private static final int LOW = 0x000000; // LOW <= all valid values. ZERO for codepoints + private static final int HIGH = 0x110000; // HIGH > all valid values. 10000 for code units. + // 110000 for codepoints + + /** + * Minimum value that can be stored in a UnicodeSet. + * + * @stable ICU 2.0 + */ + public static final int MIN_VALUE = LOW; + + /** + * Maximum value that can be stored in a UnicodeSet. + * + * @stable ICU 2.0 + */ + public static final int MAX_VALUE = HIGH - 1; + + private int len; // length used; list may be longer to minimize reallocs + private int[] list; // MUST be terminated with HIGH + private int[] rangeList; // internal buffer + private int[] buffer; // internal buffer + + // NOTE: normally the field should be of type SortedSet; but that is missing a + // public clone!! + // is not private so that UnicodeSetIterator can get access + TreeSet strings = new TreeSet(); + + /** + * The pattern representation of this set. This may not be the most economical + * pattern. It is the pattern supplied to applyPattern(), with variables + * substituted and whitespace removed. For sets constructed without + * applyPattern(), or modified using the non-pattern API, this string will be + * null, indicating that toPattern() must generate a pattern representation from + * the inversion list. + */ + + private static final int START_EXTRA = 16; // initial storage. Must be >= 0 + private static final int GROW_EXTRA = START_EXTRA; // extra amount for growth. Must be >= 0 + + private static UnicodeSet INCLUSION = null; + + private volatile BMPSet bmpSet; // The set is frozen if bmpSet or stringSpan is not null. + private volatile UnicodeSetStringSpan stringSpan; + + // ---------------------------------------------------------------- + // Public API + // ---------------------------------------------------------------- + + /** + * Constructs an empty set. + * + * @stable ICU 2.0 + */ + private UnicodeSet() { + list = new int[1 + START_EXTRA]; + list[len++] = HIGH; + } + + /** + * Constructs a copy of an existing set. + * + * @stable ICU 2.0 + */ + private UnicodeSet(UnicodeSet other) { + set(other); + } + + /** + * Constructs a set containing the given range. If end > + * start then an empty set is created. + * + * @param start first character, inclusive, of range + * @param end last character, inclusive, of range + * @stable ICU 2.0 + */ + public UnicodeSet(int start, int end) { + this(); + complement(start, end); + } + + /** + * Constructs a set from the given pattern. See the class description for the + * syntax of the pattern language. Whitespace is ignored. + * + * @param pattern a string specifying what characters are in the set + * @exception java.lang.IllegalArgumentException if the pattern contains a + * syntax error. + * @stable ICU 2.0 + */ + public UnicodeSet(String pattern) { + this(); + applyPattern(pattern, null); + } + + /** + * Make this object represent the same set as other. + * + * @param other a UnicodeSet whose value will be copied to this + * object + * @stable ICU 2.0 + */ + public UnicodeSet set(UnicodeSet other) { + checkFrozen(); + list = other.list.clone(); + len = other.len; + strings = new TreeSet(other.strings); + return this; + } + + /** + * Returns the number of elements in this set (its cardinality) Note than the + * elements of a set may include both individual codepoints and strings. + * + * @return the number of elements in this set (its cardinality). + * @stable ICU 2.0 + */ + public int size() { + int n = 0; + int count = getRangeCount(); + for (int i = 0; i < count; ++i) { + n += getRangeEnd(i) - getRangeStart(i) + 1; + } + return n + strings.size(); + } + + // for internal use, after checkFrozen has been called + private UnicodeSet add_unchecked(int start, int end) { + if (start < MIN_VALUE || start > MAX_VALUE) { + throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(start, 6)); + } + if (end < MIN_VALUE || end > MAX_VALUE) { + throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(end, 6)); + } + if (start < end) { + add(range(start, end), 2, 0); + } else if (start == end) { + add(start); + } + return this; + } + + /** + * Adds the specified character to this set if it is not already present. If + * this set already contains the specified character, the call leaves this set + * unchanged. + * + * @stable ICU 2.0 + */ + public final UnicodeSet add(int c) { + checkFrozen(); + return add_unchecked(c); + } + + // for internal use only, after checkFrozen has been called + private final UnicodeSet add_unchecked(int c) { + if (c < MIN_VALUE || c > MAX_VALUE) { + throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(c, 6)); + } + + // find smallest i such that c < list[i] + // if odd, then it is IN the set + // if even, then it is OUT of the set + int i = findCodePoint(c); + + // already in set? + if ((i & 1) != 0) + return this; + + // HIGH is 0x110000 + // assert(list[len-1] == HIGH); + + // empty = [HIGH] + // [start_0, limit_0, start_1, limit_1, HIGH] + + // [..., start_k-1, limit_k-1, start_k, limit_k, ..., HIGH] + // ^ + // list[i] + + // i == 0 means c is before the first range + + if (c == list[i] - 1) { + // c is before start of next range + list[i] = c; + // if we touched the HIGH mark, then add a new one + if (c == MAX_VALUE) { + ensureCapacity(len + 1); + list[len++] = HIGH; + } + if (i > 0 && c == list[i - 1]) { + // collapse adjacent ranges + + // [..., start_k-1, c, c, limit_k, ..., HIGH] + // ^ + // list[i] + System.arraycopy(list, i + 1, list, i - 1, len - i - 1); + len -= 2; + } + } + + else if (i > 0 && c == list[i - 1]) { + // c is after end of prior range + list[i - 1]++; + // no need to chcek for collapse here + } + + else { + // At this point we know the new char is not adjacent to + // any existing ranges, and it is not 10FFFF. + + // [..., start_k-1, limit_k-1, start_k, limit_k, ..., HIGH] + // ^ + // list[i] + + // [..., start_k-1, limit_k-1, c, c+1, start_k, limit_k, ..., HIGH] + // ^ + // list[i] + + // Don't use ensureCapacity() to save on copying. + // NOTE: This has no measurable impact on performance, + // but it might help in some usage patterns. + if (len + 2 > list.length) { + int[] temp = new int[len + 2 + GROW_EXTRA]; + if (i != 0) + System.arraycopy(list, 0, temp, 0, i); + System.arraycopy(list, i, temp, i + 2, len - i); + list = temp; + } else { + System.arraycopy(list, i, list, i + 2, len - i); + } + + list[i] = c; + list[i + 1] = c + 1; + len += 2; + } + + return this; + } + + /** + * Adds the specified multicharacter to this set if it is not already present. + * If this set already contains the multicharacter, the call leaves this set + * unchanged. Thus {@code "ch" => {"ch"}}
+ * Warning: you cannot add an empty string ("") to a UnicodeSet. + * + * @param s the source string + * @return this object, for chaining + * @stable ICU 2.0 + */ + public final UnicodeSet add(CharSequence s) { + checkFrozen(); + int cp = getSingleCP(s); + if (cp < 0) { + strings.add(s.toString()); + } else { + add_unchecked(cp, cp); + } + return this; + } + + /** + * Utility for getting code point from single code point CharSequence. See the + * public UTF16.getSingleCodePoint() + * + * @return a code point IF the string consists of a single one. otherwise + * returns -1. + * @param s to test + */ + private static int getSingleCP(CharSequence s) { + if (s.length() < 1) { + throw new IllegalArgumentException("Can't use zero-length strings in UnicodeSet"); + } + if (s.length() > 2) + return -1; + if (s.length() == 1) + return s.charAt(0); + + // at this point, len = 2 + int cp = UTF16.charAt(s, 0); + if (cp > 0xFFFF) { // is surrogate pair + return cp; + } + return -1; + } + + /** + * Complements the specified range in this set. Any character in the range will + * be removed if it is in this set, or will be added if it is not in this set. + * If {@code end > start} then an empty range is complemented, leaving the set + * unchanged. + * + * @param start first character, inclusive, of range to be removed from this + * set. + * @param end last character, inclusive, of range to be removed from this set. + * @stable ICU 2.0 + */ + public UnicodeSet complement(int start, int end) { + checkFrozen(); + if (start < MIN_VALUE || start > MAX_VALUE) { + throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(start, 6)); + } + if (end < MIN_VALUE || end > MAX_VALUE) { + throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(end, 6)); + } + if (start <= end) { + xor(range(start, end), 2, 0); + } + return this; + } + + /** + * Returns true if this set contains the given character. + * + * @param c character to be checked for containment + * @return true if the test condition is met + * @stable ICU 2.0 + */ + public boolean contains(int c) { + if (c < MIN_VALUE || c > MAX_VALUE) { + throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(c, 6)); + } + if (bmpSet != null) { + return bmpSet.contains(c); + } + if (stringSpan != null) { + return stringSpan.contains(c); + } + + /* + * // Set i to the index of the start item greater than ch // We know we will + * terminate without length test! int i = -1; while (true) { if (c < list[++i]) + * break; } + */ + + int i = findCodePoint(c); + + return ((i & 1) != 0); // return true if odd + } + + /** + * Returns the smallest value i such that c < list[i]. Caller must ensure that c + * is a legal value or this method will enter an infinite loop. This method + * performs a binary search. + * + * @param c a character in the range MIN_VALUE..MAX_VALUE inclusive + * @return the smallest integer i in the range 0..len-1, inclusive, such that c + * < list[i] + */ + private final int findCodePoint(int c) { + /* + * Examples: findCodePoint(c) set list[] c=0 1 3 4 7 8 === ============== + * =========== [] [110000] 0 0 0 0 0 0 [\u0000-\u0003] [0, 4, 110000] 1 1 1 2 2 + * 2 [\u0004-\u0007] [4, 8, 110000] 0 0 0 1 1 2 [:all:] [0, 110000] 1 1 1 1 1 1 + */ + + // Return the smallest i such that c < list[i]. Assume + // list[len - 1] == HIGH and that c is legal (0..HIGH-1). + if (c < list[0]) + return 0; + // High runner test. c is often after the last range, so an + // initial check for this condition pays off. + if (len >= 2 && c >= list[len - 2]) + return len - 1; + int lo = 0; + int hi = len - 1; + // invariant: c >= list[lo] + // invariant: c < list[hi] + for (;;) { + int i = (lo + hi) >>> 1; + if (i == lo) + return hi; + if (c < list[i]) { + hi = i; + } else { + lo = i; + } + } + } + + /** + * Retains only the elements in this set that are contained in the specified + * set. In other words, removes from this set all of its elements that are not + * contained in the specified set. This operation effectively modifies this set + * so that its value is the intersection of the two sets. + * + * @param c set that defines which elements this set will retain. + * @stable ICU 2.0 + */ + public UnicodeSet retainAll(UnicodeSet c) { + checkFrozen(); + retain(c.list, c.len, 0); + strings.retainAll(c.strings); + return this; + } + + /** + * Removes all of the elements from this set. This set will be empty after this + * call returns. + * + * @stable ICU 2.0 + */ + public UnicodeSet clear() { + checkFrozen(); + list[0] = HIGH; + len = 1; + strings.clear(); + return this; + } + + /** + * Iteration method that returns the number of ranges contained in this set. + * + * @see #getRangeStart + * @see #getRangeEnd + * @stable ICU 2.0 + */ + public int getRangeCount() { + return len / 2; + } + + /** + * Iteration method that returns the first character in the specified range of + * this set. + * + * @exception ArrayIndexOutOfBoundsException if index is outside the range + * 0..getRangeCount()-1 + * @see #getRangeCount + * @see #getRangeEnd + * @stable ICU 2.0 + */ + public int getRangeStart(int index) { + return list[index * 2]; + } + + /** + * Iteration method that returns the last character in the specified range of + * this set. + * + * @exception ArrayIndexOutOfBoundsException if index is outside the range + * 0..getRangeCount()-1 + * @see #getRangeStart + * @see #getRangeEnd + * @stable ICU 2.0 + */ + public int getRangeEnd(int index) { + return (list[index * 2 + 1] - 1); + } + + // ---------------------------------------------------------------- + // Implementation: Pattern parsing + // ---------------------------------------------------------------- + + /** + * Parses the given pattern, starting at the given position. The character at + * pattern.charAt(pos.getIndex()) must be '[', or the parse fails. Parsing + * continues until the corresponding closing ']'. If a syntax error is + * encountered between the opening and closing brace, the parse fails. Upon + * return from a successful parse, the ParsePosition is updated to point to the + * character following the closing ']', and an inversion list for the parsed + * pattern is returned. This method calls itself recursively to parse embedded + * subpatterns. + * + * @param pattern the string containing the pattern to be parsed. The portion of + * the string from pos.getIndex(), which must be a '[', to the + * corresponding closing ']', is parsed. + * @param pos upon entry, the position at which to being parsing. The + * character at pattern.charAt(pos.getIndex()) must be a '['. + * Upon return from a successful parse, pos.getIndex() is either + * the character after the closing ']' of the parsed pattern, or + * pattern.length() if the closing ']' is the last character of + * the pattern string. + * @return an inversion list for the parsed substring of pattern + * @exception java.lang.IllegalArgumentException if the parse fails. + */ + private UnicodeSet applyPattern(String pattern, ParsePosition pos) { + if ("[:age=3.2:]".equals(pattern)) { + checkFrozen(); + VersionInfo version = VersionInfo.getInstance("3.2"); + applyFilter(new VersionFilter(version), UCharacterProperty.SRC_PROPSVEC); + } else { + throw new IllegalStateException("UnicodeSet.applyPattern(unexpected pattern " + pattern + ")"); + } + + return this; + } + + // ---------------------------------------------------------------- + // Implementation: Utility methods + // ---------------------------------------------------------------- + + private void ensureCapacity(int newLen) { + if (newLen <= list.length) + return; + int[] temp = new int[newLen + GROW_EXTRA]; + System.arraycopy(list, 0, temp, 0, len); + list = temp; + } + + private void ensureBufferCapacity(int newLen) { + if (buffer != null && newLen <= buffer.length) + return; + buffer = new int[newLen + GROW_EXTRA]; + } + + /** + * Assumes start <= end. + */ + private int[] range(int start, int end) { + if (rangeList == null) { + rangeList = new int[] { start, end + 1, HIGH }; + } else { + rangeList[0] = start; + rangeList[1] = end + 1; + } + return rangeList; + } + + // ---------------------------------------------------------------- + // Implementation: Fundamental operations + // ---------------------------------------------------------------- + + // polarity = 0, 3 is normal: x xor y + // polarity = 1, 2: x xor ~y == x === y + + private UnicodeSet xor(int[] other, int otherLen, int polarity) { + ensureBufferCapacity(len + otherLen); + int i = 0, j = 0, k = 0; + int a = list[i++]; + int b; + if (polarity == 1 || polarity == 2) { + b = LOW; + if (other[j] == LOW) { // skip base if already LOW + ++j; + b = other[j]; + } + } else { + b = other[j++]; + } + // simplest of all the routines + // sort the values, discarding identicals! + while (true) { + if (a < b) { + buffer[k++] = a; + a = list[i++]; + } else if (b < a) { + buffer[k++] = b; + b = other[j++]; + } else if (a != HIGH) { // at this point, a == b + // discard both values! + a = list[i++]; + b = other[j++]; + } else { // DONE! + buffer[k++] = HIGH; + len = k; + break; + } + } + // swap list and buffer + int[] temp = list; + list = buffer; + buffer = temp; + return this; + } + + // polarity = 0 is normal: x union y + // polarity = 2: x union ~y + // polarity = 1: ~x union y + // polarity = 3: ~x union ~y + + private UnicodeSet add(int[] other, int otherLen, int polarity) { + ensureBufferCapacity(len + otherLen); + int i = 0, j = 0, k = 0; + int a = list[i++]; + int b = other[j++]; + // change from xor is that we have to check overlapping pairs + // polarity bit 1 means a is second, bit 2 means b is. + main: while (true) { + switch (polarity) { + case 0: // both first; take lower if unequal + if (a < b) { // take a + // Back up over overlapping ranges in buffer[] + if (k > 0 && a <= buffer[k - 1]) { + // Pick latter end value in buffer[] vs. list[] + a = max(list[i], buffer[--k]); + } else { + // No overlap + buffer[k++] = a; + a = list[i]; + } + i++; // Common if/else code factored out + polarity ^= 1; + } else if (b < a) { // take b + if (k > 0 && b <= buffer[k - 1]) { + b = max(other[j], buffer[--k]); + } else { + buffer[k++] = b; + b = other[j]; + } + j++; + polarity ^= 2; + } else { // a == b, take a, drop b + if (a == HIGH) + break main; + // This is symmetrical; it doesn't matter if + // we backtrack with a or b. - liu + if (k > 0 && a <= buffer[k - 1]) { + a = max(list[i], buffer[--k]); + } else { + // No overlap + buffer[k++] = a; + a = list[i]; + } + i++; + polarity ^= 1; + b = other[j++]; + polarity ^= 2; + } + break; + case 3: // both second; take higher if unequal, and drop other + if (b <= a) { // take a + if (a == HIGH) + break main; + buffer[k++] = a; + } else { // take b + if (b == HIGH) + break main; + buffer[k++] = b; + } + a = list[i++]; + polarity ^= 1; // factored common code + b = other[j++]; + polarity ^= 2; + break; + case 1: // a second, b first; if b < a, overlap + if (a < b) { // no overlap, take a + buffer[k++] = a; + a = list[i++]; + polarity ^= 1; + } else if (b < a) { // OVERLAP, drop b + b = other[j++]; + polarity ^= 2; + } else { // a == b, drop both! + if (a == HIGH) + break main; + a = list[i++]; + polarity ^= 1; + b = other[j++]; + polarity ^= 2; + } + break; + case 2: // a first, b second; if a < b, overlap + if (b < a) { // no overlap, take b + buffer[k++] = b; + b = other[j++]; + polarity ^= 2; + } else if (a < b) { // OVERLAP, drop a + a = list[i++]; + polarity ^= 1; + } else { // a == b, drop both! + if (a == HIGH) + break main; + a = list[i++]; + polarity ^= 1; + b = other[j++]; + polarity ^= 2; + } + break; + } + } + buffer[k++] = HIGH; // terminate + len = k; + // swap list and buffer + int[] temp = list; + list = buffer; + buffer = temp; + return this; + } + + // polarity = 0 is normal: x intersect y + // polarity = 2: x intersect ~y == set-minus + // polarity = 1: ~x intersect y + // polarity = 3: ~x intersect ~y + + private UnicodeSet retain(int[] other, int otherLen, int polarity) { + ensureBufferCapacity(len + otherLen); + int i = 0, j = 0, k = 0; + int a = list[i++]; + int b = other[j++]; + // change from xor is that we have to check overlapping pairs + // polarity bit 1 means a is second, bit 2 means b is. + main: while (true) { + switch (polarity) { + case 0: // both first; drop the smaller + if (a < b) { // drop a + a = list[i++]; + polarity ^= 1; + } else if (b < a) { // drop b + b = other[j++]; + polarity ^= 2; + } else { // a == b, take one, drop other + if (a == HIGH) + break main; + buffer[k++] = a; + a = list[i++]; + polarity ^= 1; + b = other[j++]; + polarity ^= 2; + } + break; + case 3: // both second; take lower if unequal + if (a < b) { // take a + buffer[k++] = a; + a = list[i++]; + polarity ^= 1; + } else if (b < a) { // take b + buffer[k++] = b; + b = other[j++]; + polarity ^= 2; + } else { // a == b, take one, drop other + if (a == HIGH) + break main; + buffer[k++] = a; + a = list[i++]; + polarity ^= 1; + b = other[j++]; + polarity ^= 2; + } + break; + case 1: // a second, b first; + if (a < b) { // NO OVERLAP, drop a + a = list[i++]; + polarity ^= 1; + } else if (b < a) { // OVERLAP, take b + buffer[k++] = b; + b = other[j++]; + polarity ^= 2; + } else { // a == b, drop both! + if (a == HIGH) + break main; + a = list[i++]; + polarity ^= 1; + b = other[j++]; + polarity ^= 2; + } + break; + case 2: // a first, b second; if a < b, overlap + if (b < a) { // no overlap, drop b + b = other[j++]; + polarity ^= 2; + } else if (a < b) { // OVERLAP, take a + buffer[k++] = a; + a = list[i++]; + polarity ^= 1; + } else { // a == b, drop both! + if (a == HIGH) + break main; + a = list[i++]; + polarity ^= 1; + b = other[j++]; + polarity ^= 2; + } + break; + } + } + buffer[k++] = HIGH; // terminate + len = k; + // swap list and buffer + int[] temp = list; + list = buffer; + buffer = temp; + return this; + } + + private static final int max(int a, int b) { + return (a > b) ? a : b; + } + + // ---------------------------------------------------------------- + // Generic filter-based scanning code + // ---------------------------------------------------------------- + + private static interface Filter { + boolean contains(int codePoint); + } + + private static final VersionInfo NO_VERSION = VersionInfo.getInstance(0, 0, 0, 0); + + private static class VersionFilter implements Filter { + VersionInfo version; + + VersionFilter(VersionInfo version) { + this.version = version; + } + + public boolean contains(int ch) { + VersionInfo v = UCharacter.getAge(ch); + // Reference comparison ok; VersionInfo caches and reuses + // unique objects. + return v != NO_VERSION && v.compareTo(version) <= 0; + } + } + + private static synchronized UnicodeSet getInclusions(int src) { + if (src != UCharacterProperty.SRC_PROPSVEC) { + throw new IllegalStateException("UnicodeSet.getInclusions(unknown src " + src + ")"); + } + + if (INCLUSION == null) { + UnicodeSet incl = new UnicodeSet(); + UCharacterProperty.INSTANCE.upropsvec_addPropertyStarts(incl); + INCLUSION = incl; + } + return INCLUSION; + } + + /** + * Generic filter-based scanning code for UCD property UnicodeSets. + */ + private UnicodeSet applyFilter(Filter filter, int src) { + // Logically, walk through all Unicode characters, noting the start + // and end of each range for which filter.contain(c) is + // true. Add each range to a set. + // + // To improve performance, use an inclusions set which + // encodes information about character ranges that are known + // to have identical properties. + // getInclusions(src) contains exactly the first characters of + // same-value ranges for the given properties "source". + + clear(); + + int startHasProperty = -1; + UnicodeSet inclusions = getInclusions(src); + int limitRange = inclusions.getRangeCount(); + + for (int j = 0; j < limitRange; ++j) { + // get current range + int start = inclusions.getRangeStart(j); + int end = inclusions.getRangeEnd(j); + + // for all the code points in the range, process + for (int ch = start; ch <= end; ++ch) { + // only add to the unicodeset on inflection points -- + // where the hasProperty value changes to false + if (filter.contains(ch)) { + if (startHasProperty < 0) { + startHasProperty = ch; + } + } else if (startHasProperty >= 0) { + add_unchecked(startHasProperty, ch - 1); + startHasProperty = -1; + } + } + } + if (startHasProperty >= 0) { + add_unchecked(startHasProperty, 0x10FFFF); + } + + return this; + } + + /** + * Is this frozen, according to the Freezable interface? + * + * @return value + * @stable ICU 3.8 + */ + public boolean isFrozen() { + return (bmpSet != null || stringSpan != null); + } + + /** + * Freeze this class, according to the Freezable interface. + * + * @return this + * @stable ICU 4.4 + */ + public UnicodeSet freeze() { + if (!isFrozen()) { + // Do most of what compact() does before freezing because + // compact() will not work when the set is frozen. + // Small modification: Don't shrink if the savings would be tiny (<=GROW_EXTRA). + + // Delete buffer first to defragment memory less. + buffer = null; + if (list.length > (len + GROW_EXTRA)) { + // Make the capacity equal to len or 1. + // We don't want to realloc of 0 size. + int capacity = (len == 0) ? 1 : len; + int[] oldList = list; + list = new int[capacity]; + for (int i = capacity; i-- > 0;) { + list[i] = oldList[i]; + } + } + + // Optimize contains() and span() and similar functions. + if (!strings.isEmpty()) { + stringSpan = new UnicodeSetStringSpan(this, new ArrayList(strings), UnicodeSetStringSpan.ALL); + } + if (stringSpan == null || !stringSpan.needsStringSpanUTF16()) { + // Optimize for code point spans. + // There are no strings, or + // all strings are irrelevant for span() etc. because + // all of each string's code points are contained in this set. + // However, fully contained strings are relevant for spanAndCount(), + // so we create both objects. + bmpSet = new BMPSet(list, len); + } + } + return this; + } + + /** + * Span a string using this UnicodeSet. + *

+ * To replace, count elements, or delete spans, see + * {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * + * @param s The string to be spanned + * @param spanCondition The span condition + * @return the length of the span + * @stable ICU 4.4 + */ + public int span(CharSequence s, SpanCondition spanCondition) { + return span(s, 0, spanCondition); + } + + /** + * Span a string using this UnicodeSet. If the start index is less than 0, span + * will start from 0. If the start index is greater than the string length, span + * returns the string length. + *

+ * To replace, count elements, or delete spans, see + * {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * + * @param s The string to be spanned + * @param start The start index that the span begins + * @param spanCondition The span condition + * @return the string index which ends the span (i.e. exclusive) + * @stable ICU 4.4 + */ + public int span(CharSequence s, int start, SpanCondition spanCondition) { + int end = s.length(); + if (start < 0) { + start = 0; + } else if (start >= end) { + return end; + } + if (bmpSet != null) { + // Frozen set without strings, or no string is relevant for span(). + return bmpSet.span(s, start, spanCondition, null); + } + if (stringSpan != null) { + return stringSpan.span(s, start, spanCondition); + } else if (!strings.isEmpty()) { + int which = spanCondition == SpanCondition.NOT_CONTAINED ? UnicodeSetStringSpan.FWD_UTF16_NOT_CONTAINED + : UnicodeSetStringSpan.FWD_UTF16_CONTAINED; + UnicodeSetStringSpan strSpan = new UnicodeSetStringSpan(this, new ArrayList(strings), which); + if (strSpan.needsStringSpanUTF16()) { + return strSpan.span(s, start, spanCondition); + } + } + + return spanCodePointsAndCount(s, start, spanCondition, null); + } + + /** + * Same as span() but also counts the smallest number of set elements on any + * path across the span. + *

+ * To replace, count elements, or delete spans, see + * {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * + * @param outCount An output-only object (must not be null) for returning the + * count. + * @return the limit (exclusive end) of the span + */ + public int spanAndCount(CharSequence s, int start, SpanCondition spanCondition, OutputInt outCount) { + if (outCount == null) { + throw new IllegalArgumentException("outCount must not be null"); + } + int end = s.length(); + if (start < 0) { + start = 0; + } else if (start >= end) { + return end; + } + if (stringSpan != null) { + // We might also have bmpSet != null, + // but fully-contained strings are relevant for counting elements. + return stringSpan.spanAndCount(s, start, spanCondition, outCount); + } else if (bmpSet != null) { + return bmpSet.span(s, start, spanCondition, outCount); + } else if (!strings.isEmpty()) { + int which = spanCondition == SpanCondition.NOT_CONTAINED ? UnicodeSetStringSpan.FWD_UTF16_NOT_CONTAINED + : UnicodeSetStringSpan.FWD_UTF16_CONTAINED; + which |= UnicodeSetStringSpan.WITH_COUNT; + UnicodeSetStringSpan strSpan = new UnicodeSetStringSpan(this, new ArrayList(strings), which); + return strSpan.spanAndCount(s, start, spanCondition, outCount); + } + + return spanCodePointsAndCount(s, start, spanCondition, outCount); + } + + private int spanCodePointsAndCount(CharSequence s, int start, SpanCondition spanCondition, OutputInt outCount) { + // Pin to 0/1 values. + boolean spanContained = (spanCondition != SpanCondition.NOT_CONTAINED); + + int c; + int next = start; + int length = s.length(); + int count = 0; + do { + c = Character.codePointAt(s, next); + if (spanContained != contains(c)) { + break; + } + ++count; + next += Character.charCount(c); + } while (next < length); + if (outCount != null) { + outCount.value = count; + } + return next; + } + + /** + * Span a string backwards (from the fromIndex) using this UnicodeSet. If the + * fromIndex is less than 0, spanBack will return 0. If fromIndex is greater + * than the string length, spanBack will start from the string length. + *

+ * To replace, count elements, or delete spans, see + * {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * + * @param s The string to be spanned + * @param fromIndex The index of the char (exclusive) that the string should + * be spanned backwards + * @param spanCondition The span condition + * @return The string index which starts the span (i.e. inclusive). + * @stable ICU 4.4 + */ + public int spanBack(CharSequence s, int fromIndex, SpanCondition spanCondition) { + if (fromIndex <= 0) { + return 0; + } + if (fromIndex > s.length()) { + fromIndex = s.length(); + } + if (bmpSet != null) { + // Frozen set without strings, or no string is relevant for spanBack(). + return bmpSet.spanBack(s, fromIndex, spanCondition); + } + if (stringSpan != null) { + return stringSpan.spanBack(s, fromIndex, spanCondition); + } else if (!strings.isEmpty()) { + int which = (spanCondition == SpanCondition.NOT_CONTAINED) ? UnicodeSetStringSpan.BACK_UTF16_NOT_CONTAINED + : UnicodeSetStringSpan.BACK_UTF16_CONTAINED; + UnicodeSetStringSpan strSpan = new UnicodeSetStringSpan(this, new ArrayList(strings), which); + if (strSpan.needsStringSpanUTF16()) { + return strSpan.spanBack(s, fromIndex, spanCondition); + } + } + + // Pin to 0/1 values. + boolean spanContained = (spanCondition != SpanCondition.NOT_CONTAINED); + + int c; + int prev = fromIndex; + do { + c = Character.codePointBefore(s, prev); + if (spanContained != contains(c)) { + break; + } + prev -= Character.charCount(c); + } while (prev > 0); + return prev; + } + + /** + * Clone a thawed version of this class, according to the Freezable interface. + * + * @return the clone, not frozen + * @stable ICU 4.4 + */ + public UnicodeSet cloneAsThawed() { + UnicodeSet result = new UnicodeSet(this); + assert !result.isFrozen(); + return result; + } + + // internal function + private void checkFrozen() { + if (isFrozen()) { + throw new UnsupportedOperationException("Attempt to modify frozen object"); + } + } + + /** + * Argument values for whether span() and similar functions continue while the + * current character is contained vs. not contained in the set. + *

+ * The functionality is straightforward for sets with only single code points, + * without strings (which is the common case): + *

    + *
  • CONTAINED and SIMPLE work the same. + *
  • CONTAINED and SIMPLE are inverses of NOT_CONTAINED. + *
  • span() and spanBack() partition any string the same way when alternating + * between span(NOT_CONTAINED) and span(either "contained" condition). + *
  • Using a complemented (inverted) set and the opposite span conditions + * yields the same results. + *
+ * When a set contains multi-code point strings, then these statements may not + * be true, depending on the strings in the set (for example, whether they + * overlap with each other) and the string that is processed. For a set with + * strings: + *
    + *
  • The complement of the set contains the opposite set of code points, but + * the same set of strings. Therefore, complementing both the set and the span + * conditions may yield different results. + *
  • When starting spans at different positions in a string (span(s, ...) vs. + * span(s+1, ...)) the ends of the spans may be different because a set string + * may start before the later position. + *
  • span(SIMPLE) may be shorter than span(CONTAINED) because it will not + * recursively try all possible paths. For example, with a set which contains + * the three strings "xy", "xya" and "ax", span("xyax", CONTAINED) will return 4 + * but span("xyax", SIMPLE) will return 3. span(SIMPLE) will never be longer + * than span(CONTAINED). + *
  • With either "contained" condition, span() and spanBack() may partition a + * string in different ways. For example, with a set which contains the two + * strings "ab" and "ba", and when processing the string "aba", span() will + * yield contained/not-contained boundaries of { 0, 2, 3 } while spanBack() will + * yield boundaries of { 0, 1, 3 }. + *
+ * Note: If it is important to get the same boundaries whether iterating forward + * or backward through a string, then either only span() should be used and the + * boundaries cached for backward operation, or an ICU BreakIterator could be + * used. + *

+ * Note: Unpaired surrogates are treated like surrogate code points. Similarly, + * set strings match only on code point boundaries, never in the middle of a + * surrogate pair. + * + * @stable ICU 4.4 + */ + public enum SpanCondition { + /** + * Continues a span() while there is no set element at the current position. + * Increments by one code point at a time. Stops before the first set element + * (character or string). (For code points only, this is like while + * contains(current)==false). + *

+ * When span() returns, the substring between where it started and the position + * it returned consists only of characters that are not in the set, and none of + * its strings overlap with the span. + * + * @stable ICU 4.4 + */ + NOT_CONTAINED, + + /** + * Spans the longest substring that is a concatenation of set elements + * (characters or strings). (For characters only, this is like while + * contains(current)==true). + *

+ * When span() returns, the substring between where it started and the position + * it returned consists only of set elements (characters or strings) that are in + * the set. + *

+ * If a set contains strings, then the span will be the longest substring for + * which there exists at least one non-overlapping concatenation of set elements + * (characters or strings). This is equivalent to a POSIX regular expression for + * (OR of each set element)*. (Java/ICU/Perl regex stops at the + * first match of an OR.) + * + * @stable ICU 4.4 + */ + CONTAINED, + + /** + * Continues a span() while there is a set element at the current position. + * Increments by the longest matching element at each position. (For characters + * only, this is like while contains(current)==true). + *

+ * When span() returns, the substring between where it started and the position + * it returned consists only of set elements (characters or strings) that are in + * the set. + *

+ * If a set only contains single characters, then this is the same as CONTAINED. + *

+ * If a set contains strings, then the span will be the longest substring with a + * match at each position with the longest single set element (character or + * string). + *

+ * Use this span condition together with other longest-match algorithms, such as + * ICU converters (ucnv_getUnicodeSet()). + * + * @stable ICU 4.4 + */ + SIMPLE, + } + +} diff --git a/src/main/java/jdk_internal/bidi/icu/util/CodePointMap.java b/src/main/java/jdk_internal/bidi/icu/util/CodePointMap.java new file mode 100755 index 00000000..358b631b --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/util/CodePointMap.java @@ -0,0 +1,498 @@ +/* + * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +// (c) 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html#License + +// created: 2018may10 Markus W. Scherer + +package jdk_internal.bidi.icu.util; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Abstract map from Unicode code points (U+0000..U+10FFFF) to integer values. + * This does not implement java.util.Map. + * + * @stable ICU 63 + */ +public abstract class CodePointMap implements Iterable { + /** + * Selectors for how getRange() should report value ranges overlapping with + * surrogates. Most users should use NORMAL. + * + * @see #getRange + * @stable ICU 63 + */ + public enum RangeOption { + /** + * getRange() enumerates all same-value ranges as stored in the map. Most users + * should use this option. + * + * @stable ICU 63 + */ + NORMAL, + /** + * getRange() enumerates all same-value ranges as stored in the map, except that + * lead surrogates (U+D800..U+DBFF) are treated as having the surrogateValue, + * which is passed to getRange() as a separate parameter. The surrogateValue is + * not transformed via filter(). See {@link Character#isHighSurrogate}. + * + *

+ * Most users should use NORMAL instead. + * + *

+ * This option is useful for maps that map surrogate code *units* to special + * values optimized for UTF-16 string processing or for special error behavior + * for unpaired surrogates, but those values are not to be associated with the + * lead surrogate code *points*. + * + * @stable ICU 63 + */ + FIXED_LEAD_SURROGATES, + /** + * getRange() enumerates all same-value ranges as stored in the map, except that + * all surrogates (U+D800..U+DFFF) are treated as having the surrogateValue, + * which is passed to getRange() as a separate parameter. The surrogateValue is + * not transformed via filter(). See {@link Character#isSurrogate}. + * + *

+ * Most users should use NORMAL instead. + * + *

+ * This option is useful for maps that map surrogate code *units* to special + * values optimized for UTF-16 string processing or for special error behavior + * for unpaired surrogates, but those values are not to be associated with the + * lead surrogate code *points*. + * + * @stable ICU 63 + */ + FIXED_ALL_SURROGATES + } + + /** + * Callback function interface: Modifies a map value. Optionally called by + * getRange(). The modified value will be returned by the getRange() function. + * + *

+ * Can be used to ignore some of the value bits, make a filter for one of + * several values, return a value index computed from the map value, etc. + * + * @see #getRange + * @see #iterator + * @stable ICU 63 + */ + public interface ValueFilter { + /** + * Modifies the map value. + * + * @param value map value + * @return modified value + * @stable ICU 63 + */ + public int apply(int value); + } + + /** + * Range iteration result data. Code points from start to end map to the same + * value. The value may have been modified by {@link ValueFilter#apply(int)}, or + * it may be the surrogateValue if a RangeOption other than "normal" was used. + * + * @see #getRange + * @see #iterator + * @stable ICU 63 + */ + public static final class Range { + private int start; + private int end; + private int value; + + /** + * Constructor. Sets start and end to -1 and value to 0. + * + * @stable ICU 63 + */ + public Range() { + start = end = -1; + value = 0; + } + + /** + * @return the start code point + * @stable ICU 63 + */ + public int getStart() { + return start; + } + + /** + * @return the (inclusive) end code point + * @stable ICU 63 + */ + public int getEnd() { + return end; + } + + /** + * @return the range value + * @stable ICU 63 + */ + public int getValue() { + return value; + } + + /** + * Sets the range. When using {@link #iterator()}, iteration will resume after + * the newly set end. + * + * @param start new start code point + * @param end new end code point + * @param value new value + * @stable ICU 63 + */ + public void set(int start, int end, int value) { + this.start = start; + this.end = end; + this.value = value; + } + } + + private final class RangeIterator implements Iterator { + private Range range = new Range(); + + @Override + public boolean hasNext() { + return -1 <= range.end && range.end < 0x10ffff; + } + + @Override + public Range next() { + if (getRange(range.end + 1, null, range)) { + return range; + } else { + throw new NoSuchElementException(); + } + } + + @Override + public final void remove() { + throw new UnsupportedOperationException(); + } + } + + /** + * Iterates over code points of a string and fetches map values. This does not + * implement java.util.Iterator. + * + *

+	 * void onString(CodePointMap map, CharSequence s, int start) {
+	 * 	CodePointMap.StringIterator iter = map.stringIterator(s, start);
+	 * 	while (iter.next()) {
+	 * 		int end = iter.getIndex(); // code point from between start and end
+	 * 		useValue(s, start, end, iter.getCodePoint(), iter.getValue());
+	 * 		start = end;
+	 * 	}
+	 * }
+	 * 
+ * + *

+ * This class is not intended for public subclassing. + * + * @stable ICU 63 + */ + public class StringIterator { + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected CharSequence s; + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected int sIndex; + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected int c; + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected int value; + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected StringIterator(CharSequence s, int sIndex) { + this.s = s; + this.sIndex = sIndex; + c = -1; + value = 0; + } + + /** + * Resets the iterator to a new string and/or a new string index. + * + * @param s string to iterate over + * @param sIndex string index where the iteration will start + * @stable ICU 63 + */ + public void reset(CharSequence s, int sIndex) { + this.s = s; + this.sIndex = sIndex; + c = -1; + value = 0; + } + + /** + * Reads the next code point, post-increments the string index, and gets a value + * from the map. Sets an implementation-defined error value if the code point is + * an unpaired surrogate. + * + * @return true if the string index was not yet at the end of the string; + * otherwise the iterator did not advance + * @stable ICU 63 + */ + public boolean next() { + if (sIndex >= s.length()) { + return false; + } + c = Character.codePointAt(s, sIndex); + sIndex += Character.charCount(c); + value = get(c); + return true; + } + + /** + * Reads the previous code point, pre-decrements the string index, and gets a + * value from the map. Sets an implementation-defined error value if the code + * point is an unpaired surrogate. + * + * @return true if the string index was not yet at the start of the string; + * otherwise the iterator did not advance + * @stable ICU 63 + */ + public boolean previous() { + if (sIndex <= 0) { + return false; + } + c = Character.codePointBefore(s, sIndex); + sIndex -= Character.charCount(c); + value = get(c); + return true; + } + + /** + * @return the string index + * @stable ICU 63 + */ + public final int getIndex() { + return sIndex; + } + + /** + * @return the code point + * @stable ICU 63 + */ + public final int getCodePoint() { + return c; + } + + /** + * @return the map value, or an implementation-defined error value if the code + * point is an unpaired surrogate + * @stable ICU 63 + */ + public final int getValue() { + return value; + } + } + + /** + * Protected no-args constructor. + * + * @stable ICU 63 + */ + protected CodePointMap() { + } + + /** + * Returns the value for a code point as stored in the map, with range checking. + * Returns an implementation-defined error value if c is not in the range + * 0..U+10FFFF. + * + * @param c the code point + * @return the map value, or an implementation-defined error value if the code + * point is not in the range 0..U+10FFFF + * @stable ICU 63 + */ + public abstract int get(int c); + + /** + * Sets the range object to a range of code points beginning with the start + * parameter. The range start is the same as the start input parameter (even if + * there are preceding code points that have the same value). The range end is + * the last code point such that all those from start to there have the same + * value. Returns false if start is not 0..U+10FFFF. Can be used to efficiently + * iterate over all same-value ranges in a map. (This is normally faster than + * iterating over code points and get()ting each value, but may be much slower + * than a data structure that stores ranges directly.) + * + *

+ * If the {@link ValueFilter} parameter is not null, then the value to be + * delivered is passed through that filter, and the return value is the end of + * the range where all values are modified to the same actual value. The value + * is unchanged if that parameter is null. + * + *

+ * Example: + * + *

+	 * int start = 0;
+	 * CodePointMap.Range range = new CodePointMap.Range();
+	 * while (map.getRange(start, null, range)) {
+	 * 	int end = range.getEnd();
+	 * 	int value = range.getValue();
+	 * 	// Work with the range start..end and its value.
+	 * 	start = end + 1;
+	 * }
+	 * 
+ * + * @param start range start + * @param filter an object that may modify the map data value, or null if the + * values from the map are to be used unmodified + * @param range the range object that will be set to the code point range and + * value + * @return true if start is 0..U+10FFFF; otherwise no new range is fetched + * @stable ICU 63 + */ + public abstract boolean getRange(int start, ValueFilter filter, Range range); + + /** + * Sets the range object to a range of code points beginning with the start + * parameter. The range start is the same as the start input parameter (even if + * there are preceding code points that have the same value). The range end is + * the last code point such that all those from start to there have the same + * value. Returns false if start is not 0..U+10FFFF. + * + *

+ * Same as the simpler {@link #getRange(int, ValueFilter, Range)} but optionally + * modifies the range if it overlaps with surrogate code points. + * + * @param start range start + * @param option defines whether surrogates are treated normally, or as + * having the surrogateValue; usually + * {@link RangeOption#NORMAL} + * @param surrogateValue value for surrogates; ignored if + * option=={@link RangeOption#NORMAL} + * @param filter an object that may modify the map data value, or null + * if the values from the map are to be used unmodified + * @param range the range object that will be set to the code point + * range and value + * @return true if start is 0..U+10FFFF; otherwise no new range is fetched + * @stable ICU 63 + */ + public boolean getRange(int start, RangeOption option, int surrogateValue, ValueFilter filter, Range range) { + assert option != null; + if (!getRange(start, filter, range)) { + return false; + } + if (option == RangeOption.NORMAL) { + return true; + } + int surrEnd = option == RangeOption.FIXED_ALL_SURROGATES ? 0xdfff : 0xdbff; + int end = range.end; + if (end < 0xd7ff || start > surrEnd) { + return true; + } + // The range overlaps with surrogates, or ends just before the first one. + if (range.value == surrogateValue) { + if (end >= surrEnd) { + // Surrogates followed by a non-surrValue range, + // or surrogates are part of a larger surrValue range. + return true; + } + } else { + if (start <= 0xd7ff) { + range.end = 0xd7ff; // Non-surrValue range ends before surrValue surrogates. + return true; + } + // Start is a surrogate with a non-surrValue code *unit* value. + // Return a surrValue code *point* range. + range.value = surrogateValue; + if (end > surrEnd) { + range.end = surrEnd; // Surrogate range ends before non-surrValue rest of range. + return true; + } + } + // See if the surrValue surrogate range can be merged with + // an immediately following range. + if (getRange(surrEnd + 1, filter, range) && range.value == surrogateValue) { + range.start = start; + return true; + } + range.start = start; + range.end = surrEnd; + range.value = surrogateValue; + return true; + } + + /** + * Convenience iterator over same-map-value code point ranges. Same as looping + * over all ranges with {@link #getRange(int, ValueFilter, Range)} without + * filtering. Adjacent ranges have different map values. + * + *

+ * The iterator always returns the same Range object. + * + * @return a Range iterator + * @stable ICU 63 + */ + @Override + public Iterator iterator() { + return new RangeIterator(); + } + + /** + * Returns an iterator (not a java.util.Iterator) over code points of a string + * for fetching map values. + * + * @param s string to iterate over + * @param sIndex string index where the iteration will start + * @return the iterator + * @stable ICU 63 + */ + public StringIterator stringIterator(CharSequence s, int sIndex) { + return new StringIterator(s, sIndex); + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/util/CodePointTrie.java b/src/main/java/jdk_internal/bidi/icu/util/CodePointTrie.java new file mode 100755 index 00000000..e84c2d0e --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/util/CodePointTrie.java @@ -0,0 +1,1357 @@ +/* + * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +// (c) 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html#License + +// created: 2018may04 Markus W. Scherer + +package jdk_internal.bidi.icu.util; + +import static jdk_internal.bidi.icu.impl.NormalizerImpl.UTF16Plus; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import jdk_internal.bidi.icu.impl.ICUBinary; + +/** + * Immutable Unicode code point trie. Fast, reasonably compact, map from Unicode + * code points (U+0000..U+10FFFF) to integer values. For details see + * http://site.icu-project.org/design/struct/utrie + * + *

+ * This class is not intended for public subclassing. + * + * @see MutableCodePointTrie + * @stable ICU 63 + */ +@SuppressWarnings("deprecation") +public abstract class CodePointTrie extends CodePointMap { + /** + * Selectors for the type of a CodePointTrie. Different trade-offs for size vs. + * speed. + * + *

+ * Use null for {@link #fromBinary} to accept any type; {@link #getType} will + * return the actual type. + * + * @see MutableCodePointTrie#buildImmutable(CodePointTrie.Type, + * CodePointTrie.ValueWidth) + * @see #fromBinary + * @see #getType + * @stable ICU 63 + */ + public enum Type { + /** + * Fast/simple/larger BMP data structure. The {@link Fast} subclasses have + * additional functions for lookup for BMP and supplementary code points. + * + * @see Fast + * @stable ICU 63 + */ + FAST, + /** + * Small/slower BMP data structure. + * + * @see Small + * @stable ICU 63 + */ + SMALL + } + + /** + * Selectors for the number of bits in a CodePointTrie data value. + * + *

+ * Use null for {@link #fromBinary} to accept any data value width; + * {@link #getValueWidth} will return the actual data value width. + * + * @stable ICU 63 + */ + public enum ValueWidth { + /** + * The trie stores 16 bits per data value. It returns them as unsigned values + * 0..0xffff=65535. + * + * @stable ICU 63 + */ + BITS_16, + /** + * The trie stores 32 bits per data value. + * + * @stable ICU 63 + */ + BITS_32, + /** + * The trie stores 8 bits per data value. It returns them as unsigned values + * 0..0xff=255. + * + * @stable ICU 63 + */ + BITS_8 + } + + private CodePointTrie(char[] index, Data data, int highStart, int index3NullOffset, int dataNullOffset) { + this.ascii = new int[ASCII_LIMIT]; + this.index = index; + this.data = data; + this.dataLength = data.getDataLength(); + this.highStart = highStart; + this.index3NullOffset = index3NullOffset; + this.dataNullOffset = dataNullOffset; + + for (int c = 0; c < ASCII_LIMIT; ++c) { + ascii[c] = data.getFromIndex(c); + } + + int nullValueOffset = dataNullOffset; + if (nullValueOffset >= dataLength) { + nullValueOffset = dataLength - HIGH_VALUE_NEG_DATA_OFFSET; + } + nullValue = data.getFromIndex(nullValueOffset); + } + + /** + * Creates a trie from its binary form, stored in the ByteBuffer starting at the + * current position. Advances the buffer position to just after the trie data. + * Inverse of {@link #toBinary(OutputStream)}. + * + *

+ * The data is copied from the buffer; later modification of the buffer will not + * affect the trie. + * + * @param type selects the trie type; this method throws an exception if + * the type does not match the binary data; use null to accept + * any type + * @param valueWidth selects the number of bits in a data value; this method + * throws an exception if the valueWidth does not match the + * binary data; use null to accept any data value width + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @see MutableCodePointTrie#MutableCodePointTrie(int, int) + * @see MutableCodePointTrie#buildImmutable(CodePointTrie.Type, + * CodePointTrie.ValueWidth) + * @see #toBinary(OutputStream) + * @stable ICU 63 + */ + public static CodePointTrie fromBinary(Type type, ValueWidth valueWidth, ByteBuffer bytes) { + ByteOrder outerByteOrder = bytes.order(); + try { + // Enough data for a trie header? + if (bytes.remaining() < 16 /* sizeof(UCPTrieHeader) */) { + throw new InternalError("Buffer too short for a CodePointTrie header"); + } + + // struct UCPTrieHeader + /** "Tri3" in big-endian US-ASCII (0x54726933) */ + int signature = bytes.getInt(); + + // Check the signature. + switch (signature) { + case 0x54726933: + // The buffer is already set to the trie data byte order. + break; + case 0x33697254: + // Temporarily reverse the byte order. + boolean isBigEndian = outerByteOrder == ByteOrder.BIG_ENDIAN; + bytes.order(isBigEndian ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN); + signature = 0x54726933; + break; + default: + throw new InternalError("Buffer does not contain a serialized CodePointTrie"); + } + + // struct UCPTrieHeader continued + /** + * Options bit field: Bits 15..12: Data length bits 19..16. Bits 11..8: Data + * null block offset bits 19..16. Bits 7..6: UCPTrieType Bits 5..3: Reserved + * (0). Bits 2..0: UCPTrieValueWidth + */ + int options = bytes.getChar(); + + /** Total length of the index tables. */ + int indexLength = bytes.getChar(); + + /** Data length bits 15..0. */ + int dataLength = bytes.getChar(); + + /** Index-3 null block offset, 0x7fff or 0xffff if none. */ + int index3NullOffset = bytes.getChar(); + + /** Data null block offset bits 15..0, 0xfffff if none. */ + int dataNullOffset = bytes.getChar(); + + /** + * First code point of the single-value range ending with U+10ffff, rounded up + * and then shifted right by SHIFT_2. + */ + int shiftedHighStart = bytes.getChar(); + // struct UCPTrieHeader end + + int typeInt = (options >> 6) & 3; + Type actualType; + switch (typeInt) { + case 0: + actualType = Type.FAST; + break; + case 1: + actualType = Type.SMALL; + break; + default: + throw new InternalError("CodePointTrie data header has an unsupported type"); + } + + int valueWidthInt = options & OPTIONS_VALUE_BITS_MASK; + ValueWidth actualValueWidth; + switch (valueWidthInt) { + case 0: + actualValueWidth = ValueWidth.BITS_16; + break; + case 1: + actualValueWidth = ValueWidth.BITS_32; + break; + case 2: + actualValueWidth = ValueWidth.BITS_8; + break; + default: + throw new InternalError("CodePointTrie data header has an unsupported value width"); + } + + if ((options & OPTIONS_RESERVED_MASK) != 0) { + throw new InternalError("CodePointTrie data header has unsupported options"); + } + + if (type == null) { + type = actualType; + } + if (valueWidth == null) { + valueWidth = actualValueWidth; + } + if (type != actualType || valueWidth != actualValueWidth) { + throw new InternalError("CodePointTrie data header has a different type or value width than required"); + } + + // Get the length values and offsets. + dataLength |= ((options & OPTIONS_DATA_LENGTH_MASK) << 4); + dataNullOffset |= ((options & OPTIONS_DATA_NULL_OFFSET_MASK) << 8); + + int highStart = shiftedHighStart << SHIFT_2; + + // Calculate the actual length, minus the header. + int actualLength = indexLength * 2; + if (valueWidth == ValueWidth.BITS_16) { + actualLength += dataLength * 2; + } else if (valueWidth == ValueWidth.BITS_32) { + actualLength += dataLength * 4; + } else { + actualLength += dataLength; + } + if (bytes.remaining() < actualLength) { + throw new InternalError("Buffer too short for the CodePointTrie data"); + } + + char[] index = ICUBinary.getChars(bytes, indexLength, 0); + switch (valueWidth) { + case BITS_16: { + char[] data16 = ICUBinary.getChars(bytes, dataLength, 0); + return type == Type.FAST ? new Fast16(index, data16, highStart, index3NullOffset, dataNullOffset) + : new Small16(index, data16, highStart, index3NullOffset, dataNullOffset); + } + case BITS_32: { + int[] data32 = ICUBinary.getInts(bytes, dataLength, 0); + return type == Type.FAST ? new Fast32(index, data32, highStart, index3NullOffset, dataNullOffset) + : new Small32(index, data32, highStart, index3NullOffset, dataNullOffset); + } + case BITS_8: { + byte[] data8 = ICUBinary.getBytes(bytes, dataLength, 0); + return type == Type.FAST ? new Fast8(index, data8, highStart, index3NullOffset, dataNullOffset) + : new Small8(index, data8, highStart, index3NullOffset, dataNullOffset); + } + default: + throw new AssertionError("should be unreachable"); + } + } finally { + bytes.order(outerByteOrder); + } + } + + /** + * Returns the trie type. + * + * @return the trie type + * @stable ICU 63 + */ + public abstract Type getType(); + + /** + * Returns the number of bits in a trie data value. + * + * @return the number of bits in a trie data value + * @stable ICU 63 + */ + public final ValueWidth getValueWidth() { + return data.getValueWidth(); + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public int get(int c) { + return data.getFromIndex(cpIndex(c)); + } + + /** + * Returns a trie value for an ASCII code point, without range checking. + * + * @param c the input code point; must be U+0000..U+007F + * @return The ASCII code point's trie value. + * @stable ICU 63 + */ + public final int asciiGet(int c) { + return ascii[c]; + } + + private static final int MAX_UNICODE = 0x10ffff; + + private static final int ASCII_LIMIT = 0x80; + + private static final int maybeFilterValue(int value, int trieNullValue, int nullValue, ValueFilter filter) { + if (value == trieNullValue) { + value = nullValue; + } else if (filter != null) { + value = filter.apply(value); + } + return value; + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final boolean getRange(int start, ValueFilter filter, Range range) { + if (start < 0 || MAX_UNICODE < start) { + return false; + } + if (start >= highStart) { + int di = dataLength - HIGH_VALUE_NEG_DATA_OFFSET; + int value = data.getFromIndex(di); + if (filter != null) { + value = filter.apply(value); + } + range.set(start, MAX_UNICODE, value); + return true; + } + + int nullValue = this.nullValue; + if (filter != null) { + nullValue = filter.apply(nullValue); + } + Type type = getType(); + + int prevI3Block = -1; + int prevBlock = -1; + int c = start; + // Initialize to make compiler happy. Real value when haveValue is true. + int trieValue = 0, value = 0; + boolean haveValue = false; + do { + int i3Block; + int i3; + int i3BlockLength; + int dataBlockLength; + if (c <= 0xffff && (type == Type.FAST || c <= SMALL_MAX)) { + i3Block = 0; + i3 = c >> FAST_SHIFT; + i3BlockLength = type == Type.FAST ? BMP_INDEX_LENGTH : SMALL_INDEX_LENGTH; + dataBlockLength = FAST_DATA_BLOCK_LENGTH; + } else { + // Use the multi-stage index. + int i1 = c >> SHIFT_1; + if (type == Type.FAST) { + assert (0xffff < c && c < highStart); + i1 += BMP_INDEX_LENGTH - OMITTED_BMP_INDEX_1_LENGTH; + } else { + assert (c < highStart && highStart > SMALL_LIMIT); + i1 += SMALL_INDEX_LENGTH; + } + i3Block = index[index[i1] + ((c >> SHIFT_2) & INDEX_2_MASK)]; + if (i3Block == prevI3Block && (c - start) >= CP_PER_INDEX_2_ENTRY) { + // The index-3 block is the same as the previous one, and filled with value. + assert ((c & (CP_PER_INDEX_2_ENTRY - 1)) == 0); + c += CP_PER_INDEX_2_ENTRY; + continue; + } + prevI3Block = i3Block; + if (i3Block == index3NullOffset) { + // This is the index-3 null block. + if (haveValue) { + if (nullValue != value) { + range.set(start, c - 1, value); + return true; + } + } else { + trieValue = this.nullValue; + value = nullValue; + haveValue = true; + } + prevBlock = dataNullOffset; + c = (c + CP_PER_INDEX_2_ENTRY) & ~(CP_PER_INDEX_2_ENTRY - 1); + continue; + } + i3 = (c >> SHIFT_3) & INDEX_3_MASK; + i3BlockLength = INDEX_3_BLOCK_LENGTH; + dataBlockLength = SMALL_DATA_BLOCK_LENGTH; + } + // Enumerate data blocks for one index-3 block. + do { + int block; + if ((i3Block & 0x8000) == 0) { + block = index[i3Block + i3]; + } else { + // 18-bit indexes stored in groups of 9 entries per 8 indexes. + int group = (i3Block & 0x7fff) + (i3 & ~7) + (i3 >> 3); + int gi = i3 & 7; + block = (index[group++] << (2 + (2 * gi))) & 0x30000; + block |= index[group + gi]; + } + if (block == prevBlock && (c - start) >= dataBlockLength) { + // The block is the same as the previous one, and filled with value. + assert ((c & (dataBlockLength - 1)) == 0); + c += dataBlockLength; + } else { + int dataMask = dataBlockLength - 1; + prevBlock = block; + if (block == dataNullOffset) { + // This is the data null block. + if (haveValue) { + if (nullValue != value) { + range.set(start, c - 1, value); + return true; + } + } else { + trieValue = this.nullValue; + value = nullValue; + haveValue = true; + } + c = (c + dataBlockLength) & ~dataMask; + } else { + int di = block + (c & dataMask); + int trieValue2 = data.getFromIndex(di); + if (haveValue) { + if (trieValue2 != trieValue) { + if (filter == null + || maybeFilterValue(trieValue2, this.nullValue, nullValue, filter) != value) { + range.set(start, c - 1, value); + return true; + } + trieValue = trieValue2; // may or may not help + } + } else { + trieValue = trieValue2; + value = maybeFilterValue(trieValue2, this.nullValue, nullValue, filter); + haveValue = true; + } + while ((++c & dataMask) != 0) { + trieValue2 = data.getFromIndex(++di); + if (trieValue2 != trieValue) { + if (filter == null + || maybeFilterValue(trieValue2, this.nullValue, nullValue, filter) != value) { + range.set(start, c - 1, value); + return true; + } + trieValue = trieValue2; // may or may not help + } + } + } + } + } while (++i3 < i3BlockLength); + } while (c < highStart); + assert (haveValue); + int di = dataLength - HIGH_VALUE_NEG_DATA_OFFSET; + int highValue = data.getFromIndex(di); + if (maybeFilterValue(highValue, this.nullValue, nullValue, filter) != value) { + --c; + } else { + c = MAX_UNICODE; + } + range.set(start, c, value); + return true; + } + + /** + * Writes a representation of the trie to the output stream. Inverse of + * {@link #fromBinary}. + * + * @param os the output stream + * @return the number of bytes written + * @stable ICU 63 + */ + public final int toBinary(OutputStream os) { + try { + DataOutputStream dos = new DataOutputStream(os); + + // Write the UCPTrieHeader + dos.writeInt(0x54726933); // signature="Tri3" + dos.writeChar( // options + ((dataLength & 0xf0000) >> 4) | ((dataNullOffset & 0xf0000) >> 8) | (getType().ordinal() << 6) + | getValueWidth().ordinal()); + dos.writeChar(index.length); + dos.writeChar(dataLength); + dos.writeChar(index3NullOffset); + dos.writeChar(dataNullOffset); + dos.writeChar(highStart >> SHIFT_2); // shiftedHighStart + int length = 16; // sizeof(UCPTrieHeader) + + for (char i : index) { + dos.writeChar(i); + } + length += index.length * 2; + length += data.write(dos); + return length; + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + /** @internal */ + static final int FAST_SHIFT = 6; + + /** + * Number of entries in a data block for code points below the fast limit. + * 64=0x40 @internal + */ + static final int FAST_DATA_BLOCK_LENGTH = 1 << FAST_SHIFT; + + /** + * Mask for getting the lower bits for the in-fast-data-block offset. @internal + */ + private static final int FAST_DATA_MASK = FAST_DATA_BLOCK_LENGTH - 1; + + /** @internal */ + private static final int SMALL_MAX = 0xfff; + + /** + * Offset from dataLength (to be subtracted) for fetching the value returned for + * out-of-range code points and ill-formed UTF-8/16. + * + * @internal + */ + private static final int ERROR_VALUE_NEG_DATA_OFFSET = 1; + /** + * Offset from dataLength (to be subtracted) for fetching the value returned for + * code points highStart..U+10FFFF. + * + * @internal + */ + private static final int HIGH_VALUE_NEG_DATA_OFFSET = 2; + + // ucptrie_impl.h + + /** The length of the BMP index table. 1024=0x400 */ + private static final int BMP_INDEX_LENGTH = 0x10000 >> FAST_SHIFT; + + static final int SMALL_LIMIT = 0x1000; + private static final int SMALL_INDEX_LENGTH = SMALL_LIMIT >> FAST_SHIFT; + + /** Shift size for getting the index-3 table offset. */ + static final int SHIFT_3 = 4; + + /** Shift size for getting the index-2 table offset. */ + private static final int SHIFT_2 = 5 + SHIFT_3; + + /** Shift size for getting the index-1 table offset. */ + private static final int SHIFT_1 = 5 + SHIFT_2; + + /** + * Difference between two shift sizes, for getting an index-2 offset from an + * index-3 offset. 5=9-4 + */ + static final int SHIFT_2_3 = SHIFT_2 - SHIFT_3; + + /** + * Difference between two shift sizes, for getting an index-1 offset from an + * index-2 offset. 5=14-9 + */ + static final int SHIFT_1_2 = SHIFT_1 - SHIFT_2; + + /** + * Number of index-1 entries for the BMP. (4) This part of the index-1 table is + * omitted from the serialized form. + */ + private static final int OMITTED_BMP_INDEX_1_LENGTH = 0x10000 >> SHIFT_1; + + /** Number of entries in an index-2 block. 32=0x20 */ + static final int INDEX_2_BLOCK_LENGTH = 1 << SHIFT_1_2; + + /** Mask for getting the lower bits for the in-index-2-block offset. */ + static final int INDEX_2_MASK = INDEX_2_BLOCK_LENGTH - 1; + + /** Number of code points per index-2 table entry. 512=0x200 */ + static final int CP_PER_INDEX_2_ENTRY = 1 << SHIFT_2; + + /** Number of entries in an index-3 block. 32=0x20 */ + static final int INDEX_3_BLOCK_LENGTH = 1 << SHIFT_2_3; + + /** Mask for getting the lower bits for the in-index-3-block offset. */ + private static final int INDEX_3_MASK = INDEX_3_BLOCK_LENGTH - 1; + + /** Number of entries in a small data block. 16=0x10 */ + static final int SMALL_DATA_BLOCK_LENGTH = 1 << SHIFT_3; + + /** Mask for getting the lower bits for the in-small-data-block offset. */ + static final int SMALL_DATA_MASK = SMALL_DATA_BLOCK_LENGTH - 1; + + // ucptrie_impl.h: Constants for use with UCPTrieHeader.options. + private static final int OPTIONS_DATA_LENGTH_MASK = 0xf000; + private static final int OPTIONS_DATA_NULL_OFFSET_MASK = 0xf00; + private static final int OPTIONS_RESERVED_MASK = 0x38; + private static final int OPTIONS_VALUE_BITS_MASK = 7; + /** + * Value for index3NullOffset which indicates that there is no index-3 null + * block. Bit 15 is unused for this value because this bit is used if the + * index-3 contains 18-bit indexes. + */ + static final int NO_INDEX3_NULL_OFFSET = 0x7fff; + static final int NO_DATA_NULL_OFFSET = 0xfffff; + + private static abstract class Data { + abstract ValueWidth getValueWidth(); + + abstract int getDataLength(); + + abstract int getFromIndex(int index); + + abstract int write(DataOutputStream dos) throws IOException; + } + + private static final class Data16 extends Data { + char[] array; + + Data16(char[] a) { + array = a; + } + + @Override + ValueWidth getValueWidth() { + return ValueWidth.BITS_16; + } + + @Override + int getDataLength() { + return array.length; + } + + @Override + int getFromIndex(int index) { + return array[index]; + } + + @Override + int write(DataOutputStream dos) throws IOException { + for (char v : array) { + dos.writeChar(v); + } + return array.length * 2; + } + } + + private static final class Data32 extends Data { + int[] array; + + Data32(int[] a) { + array = a; + } + + @Override + ValueWidth getValueWidth() { + return ValueWidth.BITS_32; + } + + @Override + int getDataLength() { + return array.length; + } + + @Override + int getFromIndex(int index) { + return array[index]; + } + + @Override + int write(DataOutputStream dos) throws IOException { + for (int v : array) { + dos.writeInt(v); + } + return array.length * 4; + } + } + + private static final class Data8 extends Data { + byte[] array; + + Data8(byte[] a) { + array = a; + } + + @Override + ValueWidth getValueWidth() { + return ValueWidth.BITS_8; + } + + @Override + int getDataLength() { + return array.length; + } + + @Override + int getFromIndex(int index) { + return array[index] & 0xff; + } + + @Override + int write(DataOutputStream dos) throws IOException { + for (byte v : array) { + dos.writeByte(v); + } + return array.length; + } + } + + /** @internal */ + private final int[] ascii; + + /** @internal */ + private final char[] index; + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected final Data data; + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected final int dataLength; + /** + * Start of the last range which ends at U+10FFFF. + * + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected final int highStart; + + /** + * Internal index-3 null block offset. Set to an impossibly high value (e.g., + * 0xffff) if there is no dedicated index-3 null block. + * + * @internal + */ + private final int index3NullOffset; + /** + * Internal data null block offset, not shifted. Set to an impossibly high value + * (e.g., 0xfffff) if there is no dedicated data null block. + * + * @internal + */ + private final int dataNullOffset; + /** @internal */ + private final int nullValue; + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected final int fastIndex(int c) { + return index[c >> FAST_SHIFT] + (c & FAST_DATA_MASK); + } + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected final int smallIndex(Type type, int c) { + // Split into two methods to make this part inline-friendly. + // In C, this part is a macro. + if (c >= highStart) { + return dataLength - HIGH_VALUE_NEG_DATA_OFFSET; + } + return internalSmallIndex(type, c); + } + + private final int internalSmallIndex(Type type, int c) { + int i1 = c >> SHIFT_1; + if (type == Type.FAST) { + assert (0xffff < c && c < highStart); + i1 += BMP_INDEX_LENGTH - OMITTED_BMP_INDEX_1_LENGTH; + } else { + assert (0 <= c && c < highStart && highStart > SMALL_LIMIT); + i1 += SMALL_INDEX_LENGTH; + } + int i3Block = index[index[i1] + ((c >> SHIFT_2) & INDEX_2_MASK)]; + int i3 = (c >> SHIFT_3) & INDEX_3_MASK; + int dataBlock; + if ((i3Block & 0x8000) == 0) { + // 16-bit indexes + dataBlock = index[i3Block + i3]; + } else { + // 18-bit indexes stored in groups of 9 entries per 8 indexes. + i3Block = (i3Block & 0x7fff) + (i3 & ~7) + (i3 >> 3); + i3 &= 7; + dataBlock = (index[i3Block++] << (2 + (2 * i3))) & 0x30000; + dataBlock |= index[i3Block + i3]; + } + return dataBlock + (c & SMALL_DATA_MASK); + } + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected abstract int cpIndex(int c); + + /** + * A CodePointTrie with {@link Type#FAST}. + * + * @stable ICU 63 + */ + public static abstract class Fast extends CodePointTrie { + private Fast(char[] index, Data data, int highStart, int index3NullOffset, int dataNullOffset) { + super(index, data, highStart, index3NullOffset, dataNullOffset); + } + + /** + * Creates a trie from its binary form. Same as + * {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} with + * {@link Type#FAST}. + * + * @param valueWidth selects the number of bits in a data value; this method + * throws an exception if the valueWidth does not match the + * binary data; use null to accept any data value width + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Fast fromBinary(ValueWidth valueWidth, ByteBuffer bytes) { + return (Fast) CodePointTrie.fromBinary(Type.FAST, valueWidth, bytes); + } + + /** + * @return {@link Type#FAST} + * @stable ICU 63 + */ + @Override + public final Type getType() { + return Type.FAST; + } + + /** + * Returns a trie value for a BMP code point (U+0000..U+FFFF), without range + * checking. Can be used to look up a value for a UTF-16 code unit if other + * parts of the string processing check for surrogates. + * + * @param c the input code point, must be U+0000..U+FFFF + * @return The BMP code point's trie value. + * @stable ICU 63 + */ + public abstract int bmpGet(int c); + + /** + * Returns a trie value for a supplementary code point (U+10000..U+10FFFF), + * without range checking. + * + * @param c the input code point, must be U+10000..U+10FFFF + * @return The supplementary code point's trie value. + * @stable ICU 63 + */ + public abstract int suppGet(int c); + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + @Override + protected final int cpIndex(int c) { + if (c >= 0) { + if (c <= 0xffff) { + return fastIndex(c); + } else if (c <= 0x10ffff) { + return smallIndex(Type.FAST, c); + } + } + return dataLength - ERROR_VALUE_NEG_DATA_OFFSET; + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final StringIterator stringIterator(CharSequence s, int sIndex) { + return new FastStringIterator(s, sIndex); + } + + private final class FastStringIterator extends StringIterator { + private FastStringIterator(CharSequence s, int sIndex) { + super(s, sIndex); + } + + @Override + public boolean next() { + if (sIndex >= s.length()) { + return false; + } + char lead = s.charAt(sIndex++); + c = lead; + int dataIndex; + if (!Character.isSurrogate(lead)) { + dataIndex = fastIndex(c); + } else { + char trail; + if (UTF16Plus.isSurrogateLead(lead) && sIndex < s.length() + && Character.isLowSurrogate(trail = s.charAt(sIndex))) { + ++sIndex; + c = Character.toCodePoint(lead, trail); + dataIndex = smallIndex(Type.FAST, c); + } else { + dataIndex = dataLength - ERROR_VALUE_NEG_DATA_OFFSET; + } + } + value = data.getFromIndex(dataIndex); + return true; + } + + @Override + public boolean previous() { + if (sIndex <= 0) { + return false; + } + char trail = s.charAt(--sIndex); + c = trail; + int dataIndex; + if (!Character.isSurrogate(trail)) { + dataIndex = fastIndex(c); + } else { + char lead; + if (!UTF16Plus.isSurrogateLead(trail) && sIndex > 0 + && Character.isHighSurrogate(lead = s.charAt(sIndex - 1))) { + --sIndex; + c = Character.toCodePoint(lead, trail); + dataIndex = smallIndex(Type.FAST, c); + } else { + dataIndex = dataLength - ERROR_VALUE_NEG_DATA_OFFSET; + } + } + value = data.getFromIndex(dataIndex); + return true; + } + } + } + + /** + * A CodePointTrie with {@link Type#SMALL}. + * + * @stable ICU 63 + */ + public static abstract class Small extends CodePointTrie { + private Small(char[] index, Data data, int highStart, int index3NullOffset, int dataNullOffset) { + super(index, data, highStart, index3NullOffset, dataNullOffset); + } + + /** + * Creates a trie from its binary form. Same as + * {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} with + * {@link Type#SMALL}. + * + * @param valueWidth selects the number of bits in a data value; this method + * throws an exception if the valueWidth does not match the + * binary data; use null to accept any data value width + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Small fromBinary(ValueWidth valueWidth, ByteBuffer bytes) { + return (Small) CodePointTrie.fromBinary(Type.SMALL, valueWidth, bytes); + } + + /** + * @return {@link Type#SMALL} + * @stable ICU 63 + */ + @Override + public final Type getType() { + return Type.SMALL; + } + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + @Override + protected final int cpIndex(int c) { + if (c >= 0) { + if (c <= SMALL_MAX) { + return fastIndex(c); + } else if (c <= 0x10ffff) { + return smallIndex(Type.SMALL, c); + } + } + return dataLength - ERROR_VALUE_NEG_DATA_OFFSET; + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final StringIterator stringIterator(CharSequence s, int sIndex) { + return new SmallStringIterator(s, sIndex); + } + + private final class SmallStringIterator extends StringIterator { + private SmallStringIterator(CharSequence s, int sIndex) { + super(s, sIndex); + } + + @Override + public boolean next() { + if (sIndex >= s.length()) { + return false; + } + char lead = s.charAt(sIndex++); + c = lead; + int dataIndex; + if (!Character.isSurrogate(lead)) { + dataIndex = cpIndex(c); + } else { + char trail; + if (UTF16Plus.isSurrogateLead(lead) && sIndex < s.length() + && Character.isLowSurrogate(trail = s.charAt(sIndex))) { + ++sIndex; + c = Character.toCodePoint(lead, trail); + dataIndex = smallIndex(Type.SMALL, c); + } else { + dataIndex = dataLength - ERROR_VALUE_NEG_DATA_OFFSET; + } + } + value = data.getFromIndex(dataIndex); + return true; + } + + @Override + public boolean previous() { + if (sIndex <= 0) { + return false; + } + char trail = s.charAt(--sIndex); + c = trail; + int dataIndex; + if (!Character.isSurrogate(trail)) { + dataIndex = cpIndex(c); + } else { + char lead; + if (!UTF16Plus.isSurrogateLead(trail) && sIndex > 0 + && Character.isHighSurrogate(lead = s.charAt(sIndex - 1))) { + --sIndex; + c = Character.toCodePoint(lead, trail); + dataIndex = smallIndex(Type.SMALL, c); + } else { + dataIndex = dataLength - ERROR_VALUE_NEG_DATA_OFFSET; + } + } + value = data.getFromIndex(dataIndex); + return true; + } + } + } + + /** + * A CodePointTrie with {@link Type#FAST} and {@link ValueWidth#BITS_16}. + * + * @stable ICU 63 + */ + public static final class Fast16 extends Fast { + private final char[] dataArray; + + Fast16(char[] index, char[] data16, int highStart, int index3NullOffset, int dataNullOffset) { + super(index, new Data16(data16), highStart, index3NullOffset, dataNullOffset); + this.dataArray = data16; + } + + /** + * Creates a trie from its binary form. Same as + * {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} with + * {@link Type#FAST} and {@link ValueWidth#BITS_16}. + * + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Fast16 fromBinary(ByteBuffer bytes) { + return (Fast16) CodePointTrie.fromBinary(Type.FAST, ValueWidth.BITS_16, bytes); + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final int get(int c) { + return dataArray[cpIndex(c)]; + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final int bmpGet(int c) { + assert 0 <= c && c <= 0xffff; + return dataArray[fastIndex(c)]; + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final int suppGet(int c) { + assert 0x10000 <= c && c <= 0x10ffff; + return dataArray[smallIndex(Type.FAST, c)]; + } + } + + /** + * A CodePointTrie with {@link Type#FAST} and {@link ValueWidth#BITS_32}. + * + * @stable ICU 63 + */ + public static final class Fast32 extends Fast { + private final int[] dataArray; + + Fast32(char[] index, int[] data32, int highStart, int index3NullOffset, int dataNullOffset) { + super(index, new Data32(data32), highStart, index3NullOffset, dataNullOffset); + this.dataArray = data32; + } + + /** + * Creates a trie from its binary form. Same as + * {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} with + * {@link Type#FAST} and {@link ValueWidth#BITS_32}. + * + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Fast32 fromBinary(ByteBuffer bytes) { + return (Fast32) CodePointTrie.fromBinary(Type.FAST, ValueWidth.BITS_32, bytes); + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final int get(int c) { + return dataArray[cpIndex(c)]; + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final int bmpGet(int c) { + assert 0 <= c && c <= 0xffff; + return dataArray[fastIndex(c)]; + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final int suppGet(int c) { + assert 0x10000 <= c && c <= 0x10ffff; + return dataArray[smallIndex(Type.FAST, c)]; + } + } + + /** + * A CodePointTrie with {@link Type#FAST} and {@link ValueWidth#BITS_8}. + * + * @stable ICU 63 + */ + public static final class Fast8 extends Fast { + private final byte[] dataArray; + + Fast8(char[] index, byte[] data8, int highStart, int index3NullOffset, int dataNullOffset) { + super(index, new Data8(data8), highStart, index3NullOffset, dataNullOffset); + this.dataArray = data8; + } + + /** + * Creates a trie from its binary form. Same as + * {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} with + * {@link Type#FAST} and {@link ValueWidth#BITS_8}. + * + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Fast8 fromBinary(ByteBuffer bytes) { + return (Fast8) CodePointTrie.fromBinary(Type.FAST, ValueWidth.BITS_8, bytes); + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final int get(int c) { + return dataArray[cpIndex(c)] & 0xff; + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final int bmpGet(int c) { + assert 0 <= c && c <= 0xffff; + return dataArray[fastIndex(c)] & 0xff; + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final int suppGet(int c) { + assert 0x10000 <= c && c <= 0x10ffff; + return dataArray[smallIndex(Type.FAST, c)] & 0xff; + } + } + + /** + * A CodePointTrie with {@link Type#SMALL} and {@link ValueWidth#BITS_16}. + * + * @stable ICU 63 + */ + public static final class Small16 extends Small { + Small16(char[] index, char[] data16, int highStart, int index3NullOffset, int dataNullOffset) { + super(index, new Data16(data16), highStart, index3NullOffset, dataNullOffset); + } + + /** + * Creates a trie from its binary form. Same as + * {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} with + * {@link Type#SMALL} and {@link ValueWidth#BITS_16}. + * + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Small16 fromBinary(ByteBuffer bytes) { + return (Small16) CodePointTrie.fromBinary(Type.SMALL, ValueWidth.BITS_16, bytes); + } + } + + /** + * A CodePointTrie with {@link Type#SMALL} and {@link ValueWidth#BITS_32}. + * + * @stable ICU 63 + */ + public static final class Small32 extends Small { + Small32(char[] index, int[] data32, int highStart, int index3NullOffset, int dataNullOffset) { + super(index, new Data32(data32), highStart, index3NullOffset, dataNullOffset); + } + + /** + * Creates a trie from its binary form. Same as + * {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} with + * {@link Type#SMALL} and {@link ValueWidth#BITS_32}. + * + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Small32 fromBinary(ByteBuffer bytes) { + return (Small32) CodePointTrie.fromBinary(Type.SMALL, ValueWidth.BITS_32, bytes); + } + } + + /** + * A CodePointTrie with {@link Type#SMALL} and {@link ValueWidth#BITS_8}. + * + * @stable ICU 63 + */ + public static final class Small8 extends Small { + Small8(char[] index, byte[] data8, int highStart, int index3NullOffset, int dataNullOffset) { + super(index, new Data8(data8), highStart, index3NullOffset, dataNullOffset); + } + + /** + * Creates a trie from its binary form. Same as + * {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} with + * {@link Type#SMALL} and {@link ValueWidth#BITS_8}. + * + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Small8 fromBinary(ByteBuffer bytes) { + return (Small8) CodePointTrie.fromBinary(Type.SMALL, ValueWidth.BITS_8, bytes); + } + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/util/OutputInt.java b/src/main/java/jdk_internal/bidi/icu/util/OutputInt.java new file mode 100755 index 00000000..433bf28a --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/util/OutputInt.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ +package jdk_internal.bidi.icu.util; + +/** + * Simple struct-like class for int output parameters. Like + * Output<Integer> but without auto-boxing. + * + * @internal but could become public deprecated This API is ICU internal only. + */ +public class OutputInt { + + /** + * The value field. + * + * @internal deprecated This API is ICU internal only. + */ + public int value; +} diff --git a/src/main/java/jdk_internal/bidi/icu/util/VersionInfo.java b/src/main/java/jdk_internal/bidi/icu/util/VersionInfo.java new file mode 100755 index 00000000..d6abf225 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/util/VersionInfo.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + ******************************************************************************* + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.util; + +import java.util.HashMap; + +/** + * Class to store version numbers of the form major.minor.milli.micro. + * + * @author synwee + * @stable ICU 2.6 + */ +public final class VersionInfo { + // public data members ------------------------------------------------- + + /** + * Data version string for ICU's internal data. Used for appending to data path + * (e.g. icudt43b) + * + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + public static final String ICU_DATA_VERSION_PATH = "67b"; + + // public methods ------------------------------------------------------ + + /** + * Returns an instance of VersionInfo with the argument version. + * + * @param version version String in the format of "major.minor.milli.micro" or + * "major.minor.milli" or "major.minor" or "major", where major, + * minor, milli, micro are non-negative numbers {@literal <=} + * 255. If the trailing version numbers are not specified they + * are taken as 0s. E.g. Version "3.1" is equivalent to + * "3.1.0.0". + * @return an instance of VersionInfo with the argument version. + * @exception throws an IllegalArgumentException when the argument version is + * not in the right format + * @stable ICU 2.6 + */ + public static VersionInfo getInstance(String version) { + int length = version.length(); + int array[] = { 0, 0, 0, 0 }; + int count = 0; + int index = 0; + + while (count < 4 && index < length) { + char c = version.charAt(index); + if (c == '.') { + count++; + } else { + c -= '0'; + if (c < 0 || c > 9) { + throw new IllegalArgumentException(INVALID_VERSION_NUMBER_); + } + array[count] *= 10; + array[count] += c; + } + index++; + } + if (index != length) { + throw new IllegalArgumentException( + "Invalid version number: String '" + version + "' exceeds version format"); + } + for (int i = 0; i < 4; i++) { + if (array[i] < 0 || array[i] > 255) { + throw new IllegalArgumentException(INVALID_VERSION_NUMBER_); + } + } + + return getInstance(array[0], array[1], array[2], array[3]); + } + + /** + * Returns an instance of VersionInfo with the argument version. + * + * @param major major version, non-negative number {@literal <=} 255. + * @param minor minor version, non-negative number {@literal <=} 255. + * @param milli milli version, non-negative number {@literal <=} 255. + * @param micro micro version, non-negative number {@literal <=} 255. + * @exception throws an IllegalArgumentException when either arguments are + * negative or {@literal >} 255 + * @stable ICU 2.6 + */ + public static VersionInfo getInstance(int major, int minor, int milli, int micro) { + // checks if it is in the hashmap + // else + if (major < 0 || major > 255 || minor < 0 || minor > 255 || milli < 0 || milli > 255 || micro < 0 + || micro > 255) { + throw new IllegalArgumentException(INVALID_VERSION_NUMBER_); + } + int version = getInt(major, minor, milli, micro); + Integer key = Integer.valueOf(version); + Object result = MAP_.get(key); + if (result == null) { + result = new VersionInfo(version); + MAP_.put(key, result); + } + return (VersionInfo) result; + } + + /** + * Compares other with this VersionInfo. + * + * @param other VersionInfo to be compared + * @return 0 if the argument is a VersionInfo object that has version + * information equal to this object. Less than 0 if the argument is a + * VersionInfo object that has version information greater than this + * object. Greater than 0 if the argument is a VersionInfo object that + * has version information less than this object. + * @stable ICU 2.6 + */ + public int compareTo(VersionInfo other) { + return m_version_ - other.m_version_; + } + + // private data members ---------------------------------------------- + + /** + * Version number stored as a byte for each of the major, minor, milli and micro + * numbers in the 32 bit int. Most significant for the major and the least + * significant contains the micro numbers. + */ + private int m_version_; + /** + * Map of singletons + */ + private static final HashMap MAP_ = new HashMap<>(); + /** + * Error statement string + */ + private static final String INVALID_VERSION_NUMBER_ = "Invalid version number: Version number may be negative or greater than 255"; + + // private constructor ----------------------------------------------- + + /** + * Constructor with int + * + * @param compactversion a 32 bit int with each byte representing a number + */ + private VersionInfo(int compactversion) { + m_version_ = compactversion; + } + + /** + * Gets the int from the version numbers + * + * @param major non-negative version number + * @param minor non-negativeversion number + * @param milli non-negativeversion number + * @param micro non-negativeversion number + */ + private static int getInt(int major, int minor, int milli, int micro) { + return (major << 24) | (minor << 16) | (milli << 8) | micro; + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglerBidiReorder.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglerBidiReorder.java new file mode 100755 index 00000000..4a480072 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglerBidiReorder.java @@ -0,0 +1,87 @@ +package net.lax1dude.eaglercraft.v1_8; + +import jdk_internal.bidi.Bidi; + +/** + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class EaglerBidiReorder { + + /** + * Taken from minecraft 1.6 + */ + public static String bidiReorder(String par1Str) { + if (par1Str != null && Bidi.requiresBidi(par1Str.toCharArray(), 0, par1Str.length())) { + Bidi bidi = new Bidi(par1Str, -2); + byte[] abyte = new byte[bidi.getRunCount()]; + String[] astring = new String[abyte.length]; + int i; + + for (int j = 0; j < abyte.length; ++j) { + int k = bidi.getRunStart(j); + i = bidi.getRunLimit(j); + int l = bidi.getRunLevel(j); + String s1 = par1Str.substring(k, i); + abyte[j] = (byte) l; + astring[j] = s1; + } + + String[] astring1 = (String[]) astring.clone(); + Bidi.reorderVisually(abyte, 0, astring, 0, abyte.length); + StringBuilder stringbuilder = new StringBuilder(); + i = 0; + + while (i < astring.length) { + byte b0 = abyte[i]; + int i1 = 0; + + while (true) { + if (i1 < astring1.length) { + if (!astring1[i1].equals(astring[i])) { + ++i1; + continue; + } + + b0 = abyte[i1]; + } + + if ((b0 & 1) == 0) { + stringbuilder.append(astring[i]); + } else { + for (i1 = astring[i].length() - 1; i1 >= 0; --i1) { + char c0 = astring[i].charAt(i1); + + if (c0 == 40) { + c0 = 41; + } else if (c0 == 41) { + c0 = 40; + } + + stringbuilder.append(c0); + } + } + + ++i; + break; + } + } + + return stringbuilder.toString(); + } else { + return par1Str; + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglerZLIB.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglerZLIB.java index 49a8dbb2..94100a5c 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglerZLIB.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglerZLIB.java @@ -26,15 +26,33 @@ public class EaglerZLIB { public static OutputStream newDeflaterOutputStream(OutputStream os) throws IOException { return PlatformRuntime.newDeflaterOutputStream(os); } - + + public static int deflateFull(byte[] input, byte[] output) throws IOException { + return PlatformRuntime.deflateFull(input, 0, input.length, output, 0, output.length); + } + + public static int deflateFull(byte[] input, int inputOff, int inputLen, byte[] output, int outputOff, + int outputLen) throws IOException { + return PlatformRuntime.deflateFull(input, inputOff, inputLen, output, outputOff, outputLen); + } + public static OutputStream newGZIPOutputStream(OutputStream os) throws IOException { return PlatformRuntime.newGZIPOutputStream(os); } - + public static InputStream newInflaterInputStream(InputStream is) throws IOException { return PlatformRuntime.newInflaterInputStream(is); } - + + public static int inflateFull(byte[] input, byte[] output) throws IOException { + return PlatformRuntime.inflateFull(input, 0, input.length, output, 0, output.length); + } + + public static int inflateFull(byte[] input, int inputOff, int inputLen, byte[] output, int outputOff, + int outputLen) throws IOException { + return PlatformRuntime.inflateFull(input, inputOff, inputLen, output, outputOff, outputLen); + } + public static InputStream newGZIPInputStream(InputStream is) throws IOException { return PlatformRuntime.newGZIPInputStream(is); } diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftVersion.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftVersion.java index 6434d403..430ff1d3 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftVersion.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftVersion.java @@ -10,7 +10,7 @@ public class EaglercraftVersion { /// Customize these to fit your fork: public static final String projectForkName = "EaglercraftX"; - public static final String projectForkVersion = "u46"; + public static final String projectForkVersion = "u47"; public static final String projectForkVendor = "lax1dude"; public static final String projectForkURL = "https://gitlab.com/lax1dude/eaglercraftx-1.8"; @@ -20,20 +20,20 @@ public class EaglercraftVersion { public static final String projectOriginName = "EaglercraftX"; public static final String projectOriginAuthor = "lax1dude"; public static final String projectOriginRevision = "1.8"; - public static final String projectOriginVersion = "u46"; + public static final String projectOriginVersion = "u47"; public static final String projectOriginURL = "https://gitlab.com/lax1dude/eaglercraftx-1.8"; // rest in peace // EPK Version Identifier - public static final String EPKVersionIdentifier = "u46"; // Set to null to disable EPK version check + public static final String EPKVersionIdentifier = "u47"; // Set to null to disable EPK version check // Updating configuration public static final boolean enableUpdateService = true; public static final String updateBundlePackageName = "net.lax1dude.eaglercraft.v1_8.client"; - public static final int updateBundlePackageVersionInt = 46; + public static final int updateBundlePackageVersionInt = 47; public static final String updateLatestLocalStorageKey = "latestUpdate_" + updateBundlePackageName; diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ByteBuffer.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ByteBuffer.java index 8b4f843d..bf00ed96 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ByteBuffer.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ByteBuffer.java @@ -2,7 +2,7 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer; /** - * Copyright (c) 2022 lax1dude. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -16,88 +16,100 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer; * POSSIBILITY OF SUCH DAMAGE. * */ -public interface ByteBuffer extends Buffer { +public abstract class ByteBuffer implements Buffer { - ByteBuffer duplicate(); + public abstract ByteBuffer duplicate(); - byte get(); + public abstract byte get(); - ByteBuffer put(byte b); + public abstract ByteBuffer put(byte b); - byte get(int index); + public abstract byte get(int index); - ByteBuffer put(int index, byte b); + public abstract ByteBuffer put(int index, byte b); - ByteBuffer get(byte[] dst, int offset, int length); + public abstract ByteBuffer get(byte[] dst, int offset, int length); - ByteBuffer get(byte[] dst); + public abstract ByteBuffer get(byte[] dst); - ByteBuffer put(ByteBuffer src); + public abstract ByteBuffer put(ByteBuffer src); - ByteBuffer put(byte[] src, int offset, int length); + public abstract ByteBuffer put(byte[] src, int offset, int length); - ByteBuffer put(byte[] src); + public abstract ByteBuffer put(byte[] src); - char getChar(); + public abstract char getChar(); - ByteBuffer putChar(char value); + public abstract ByteBuffer putChar(char value); - char getChar(int index); + public abstract char getChar(int index); - ByteBuffer putChar(int index, char value); + public abstract ByteBuffer putChar(int index, char value); - short getShort(); + public abstract short getShort(); - ByteBuffer putShort(short value); + public abstract ByteBuffer putShort(short value); - short getShort(int index); + public abstract short getShort(int index); - ByteBuffer putShort(int index, short value); + public abstract ByteBuffer putShort(int index, short value); - ShortBuffer asShortBuffer(); + public abstract ShortBuffer asShortBuffer(); - int getInt(); + public abstract int getInt(); - ByteBuffer putInt(int value); + public abstract ByteBuffer putInt(int value); - int getInt(int index); + public abstract int getInt(int index); - ByteBuffer putInt(int index, int value); + public abstract ByteBuffer putInt(int index, int value); - IntBuffer asIntBuffer(); + public abstract IntBuffer asIntBuffer(); - long getLong(); + public abstract long getLong(); - ByteBuffer putLong(long value); + public abstract ByteBuffer putLong(long value); - long getLong(int index); + public abstract long getLong(int index); - ByteBuffer putLong(int index, long value); + public abstract ByteBuffer putLong(int index, long value); - float getFloat(); + public abstract float getFloat(); - ByteBuffer putFloat(float value); + public abstract ByteBuffer putFloat(float value); - float getFloat(int index); + public abstract float getFloat(int index); - ByteBuffer putFloat(int index, float value); + public abstract ByteBuffer putFloat(int index, float value); - FloatBuffer asFloatBuffer(); + public abstract FloatBuffer asFloatBuffer(); - ByteBuffer mark(); + public abstract ByteBuffer mark(); - ByteBuffer reset(); + public abstract ByteBuffer reset(); - ByteBuffer clear(); + public abstract ByteBuffer clear(); - ByteBuffer flip(); + public abstract ByteBuffer flip(); - ByteBuffer rewind(); + public abstract ByteBuffer rewind(); - ByteBuffer limit(int newLimit); + public abstract ByteBuffer limit(int newLimit); - ByteBuffer position(int newPosition); + public abstract int limit(); - byte[] array(); + public abstract ByteBuffer position(int newPosition); + + public abstract int position(); + + public abstract int remaining(); + + public abstract boolean hasRemaining(); + + public abstract int capacity(); + + public abstract boolean hasArray(); + + public abstract byte[] array(); } diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/FloatBuffer.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/FloatBuffer.java index 6d9a9374..e34484eb 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/FloatBuffer.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/FloatBuffer.java @@ -1,7 +1,7 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer; /** - * Copyright (c) 2022 lax1dude. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -15,49 +15,61 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer; * POSSIBILITY OF SUCH DAMAGE. * */ -public interface FloatBuffer extends Buffer { +public abstract class FloatBuffer implements Buffer { - FloatBuffer duplicate(); + public abstract FloatBuffer duplicate(); - float get(); + public abstract float get(); - FloatBuffer put(float b); + public abstract FloatBuffer put(float b); - float get(int index); + public abstract float get(int index); - FloatBuffer put(int index, float b); + public abstract FloatBuffer put(int index, float b); - float getElement(int index); + public abstract float getElement(int index); - void putElement(int index, float value); + public abstract void putElement(int index, float value); - FloatBuffer get(float[] dst, int offset, int length); + public abstract FloatBuffer get(float[] dst, int offset, int length); - FloatBuffer get(float[] dst); + public abstract FloatBuffer get(float[] dst); - FloatBuffer put(FloatBuffer src); + public abstract FloatBuffer put(FloatBuffer src); - FloatBuffer put(float[] src, int offset, int length); + public abstract FloatBuffer put(float[] src, int offset, int length); - FloatBuffer put(float[] src); + public abstract FloatBuffer put(float[] src); - boolean isDirect(); + public abstract boolean isDirect(); - FloatBuffer mark(); + public abstract FloatBuffer mark(); - FloatBuffer reset(); + public abstract FloatBuffer reset(); - FloatBuffer clear(); + public abstract FloatBuffer clear(); - FloatBuffer flip(); + public abstract FloatBuffer flip(); - FloatBuffer rewind(); + public abstract FloatBuffer rewind(); - FloatBuffer limit(int newLimit); + public abstract FloatBuffer limit(int newLimit); - FloatBuffer position(int newPosition); + public abstract int limit(); - float[] array(); + public abstract FloatBuffer position(int newPosition); + + public abstract int position(); + + public abstract int remaining(); + + public abstract boolean hasRemaining(); + + public abstract int capacity(); + + public abstract boolean hasArray(); + + public abstract float[] array(); } diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/IntBuffer.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/IntBuffer.java index 44e5967d..8414e4ee 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/IntBuffer.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/IntBuffer.java @@ -15,49 +15,61 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer; * POSSIBILITY OF SUCH DAMAGE. * */ -public interface IntBuffer extends Buffer { +public abstract class IntBuffer implements Buffer { - IntBuffer duplicate(); + public abstract IntBuffer duplicate(); - int get(); + public abstract int get(); - IntBuffer put(int b); + public abstract IntBuffer put(int b); - int get(int index); + public abstract int get(int index); - IntBuffer put(int index, int b); + public abstract IntBuffer put(int index, int b); - int getElement(int index); + public abstract int getElement(int index); - void putElement(int index, int value); + public abstract void putElement(int index, int value); - IntBuffer get(int[] dst, int offset, int length); + public abstract IntBuffer get(int[] dst, int offset, int length); - IntBuffer get(int[] dst); + public abstract IntBuffer get(int[] dst); - IntBuffer put(IntBuffer src); + public abstract IntBuffer put(IntBuffer src); - IntBuffer put(int[] src, int offset, int length); + public abstract IntBuffer put(int[] src, int offset, int length); - IntBuffer put(int[] src); + public abstract IntBuffer put(int[] src); - boolean isDirect(); + public abstract boolean isDirect(); - IntBuffer mark(); + public abstract IntBuffer mark(); - IntBuffer reset(); + public abstract IntBuffer reset(); - IntBuffer clear(); + public abstract IntBuffer clear(); - IntBuffer flip(); + public abstract IntBuffer flip(); - IntBuffer rewind(); + public abstract IntBuffer rewind(); - IntBuffer limit(int newLimit); + public abstract IntBuffer limit(int newLimit); - IntBuffer position(int newPosition); + public abstract int limit(); - int[] array(); + public abstract IntBuffer position(int newPosition); + + public abstract int position(); + + public abstract int remaining(); + + public abstract boolean hasRemaining(); + + public abstract int capacity(); + + public abstract boolean hasArray(); + + public abstract int[] array(); } diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ShortBuffer.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ShortBuffer.java index bb158828..b9649f6a 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ShortBuffer.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ShortBuffer.java @@ -1,7 +1,7 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer; /** - * Copyright (c) 2022 lax1dude. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -15,48 +15,60 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer; * POSSIBILITY OF SUCH DAMAGE. * */ -public interface ShortBuffer extends Buffer { +public abstract class ShortBuffer implements Buffer { - ShortBuffer duplicate(); + public abstract ShortBuffer duplicate(); - short get(); + public abstract short get(); - ShortBuffer put(short b); + public abstract ShortBuffer put(short b); - short get(int index); + public abstract short get(int index); - ShortBuffer put(int index, short b); + public abstract ShortBuffer put(int index, short b); - short getElement(int index); + public abstract short getElement(int index); - void putElement(int index, short value); + public abstract void putElement(int index, short value); - ShortBuffer get(short[] dst, int offset, int length); + public abstract ShortBuffer get(short[] dst, int offset, int length); - ShortBuffer get(short[] dst); + public abstract ShortBuffer get(short[] dst); - ShortBuffer put(ShortBuffer src); + public abstract ShortBuffer put(ShortBuffer src); - ShortBuffer put(short[] src, int offset, int length); + public abstract ShortBuffer put(short[] src, int offset, int length); - ShortBuffer put(short[] src); + public abstract ShortBuffer put(short[] src); - boolean isDirect(); + public abstract boolean isDirect(); - ShortBuffer mark(); + public abstract ShortBuffer mark(); - ShortBuffer reset(); + public abstract ShortBuffer reset(); - ShortBuffer clear(); + public abstract ShortBuffer clear(); - ShortBuffer flip(); + public abstract ShortBuffer flip(); - ShortBuffer rewind(); + public abstract ShortBuffer rewind(); - ShortBuffer limit(int newLimit); + public abstract ShortBuffer limit(int newLimit); - ShortBuffer position(int newPosition); + public abstract int limit(); - short[] array(); + public abstract ShortBuffer position(int newPosition); + + public abstract int position(); + + public abstract int remaining(); + + public abstract boolean hasRemaining(); + + public abstract int capacity(); + + public abstract boolean hasArray(); + + public abstract short[] array(); } diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerTextureAtlasSprite.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerTextureAtlasSprite.java index 910f379b..b9cd3758 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerTextureAtlasSprite.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerTextureAtlasSprite.java @@ -1,10 +1,10 @@ package net.lax1dude.eaglercraft.v1_8.minecraft; import java.io.IOException; -import java.util.Iterator; import java.util.List; import java.util.concurrent.Callable; +import com.carrotsearch.hppc.cursors.IntCursor; import com.google.common.collect.Lists; import net.lax1dude.eaglercraft.v1_8.HString; @@ -228,10 +228,8 @@ public class EaglerTextureAtlasSprite { int l = i; this.height = this.width; if (meta.getFrameCount() > 0) { - Iterator iterator = meta.getFrameIndexSet().iterator(); - - while (iterator.hasNext()) { - int i1 = iterator.next().intValue(); + for (IntCursor cur : meta.getFrameIndexSet()) { + int i1 = cur.value; if (i1 >= j1) { throw new RuntimeException("invalid frameindex " + i1); } diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglerMeshLoader.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglerMeshLoader.java index c2d1ad37..3a243e71 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglerMeshLoader.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglerMeshLoader.java @@ -49,6 +49,7 @@ public class EaglerMeshLoader implements IResourceManagerReloadListener { if(theMesh == null) { theMesh = new HighPolyMesh(); reloadMesh(meshLoc, theMesh, Minecraft.getMinecraft().getResourceManager()); + meshCache.put(meshLoc, theMesh); } meshLoc.cachedPointerType = ResourceLocation.CACHED_POINTER_EAGLER_MESH; meshLoc.cachedPointer = theMesh; diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglercraftGPU.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglercraftGPU.java index c44464f6..d0ab885f 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglercraftGPU.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglercraftGPU.java @@ -7,8 +7,8 @@ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; import net.lax1dude.eaglercraft.v1_8.log4j.Logger; import net.minecraft.util.MathHelper; -import java.util.HashMap; -import java.util.Map; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import net.lax1dude.eaglercraft.v1_8.EagRuntime; import net.lax1dude.eaglercraft.v1_8.internal.GLObjectMap; @@ -213,15 +213,18 @@ public class EaglercraftGPU { ++GlStateManager.stateNormalSerial; } - private static final Map stringCache = new HashMap<>(); + private static final IntObjectMap stringCache = new IntObjectHashMap<>(); public static final String glGetString(int param) { String str = stringCache.get(param); if(str == null) { str = _wglGetString(param); + if(str == null) { + str = ""; + } stringCache.put(param, str); } - return str; + return str.length() == 0 ? null : str; } public static final void glGetInteger(int param, int[] values) { diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/WorldRenderer.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/WorldRenderer.java index e766dc22..699888b0 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/WorldRenderer.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/WorldRenderer.java @@ -3,9 +3,10 @@ package net.lax1dude.eaglercraft.v1_8.opengl; import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer; import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer; import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer; -import java.util.Arrays; import java.util.BitSet; -import java.util.Comparator; +import java.util.function.IntBinaryOperator; + +import com.carrotsearch.hppc.sorting.QuickSort; import net.lax1dude.eaglercraft.v1_8.EagRuntime; import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; @@ -84,12 +85,37 @@ public class WorldRenderer { } } + private float[] sortArrayCacheA = null; + private int[] sortArrayCacheB = null; + private BitSet sortBitSetCache = null; + private final IntBinaryOperator sortArrayCacheLambda = this::sortFunction_func_181674_a; + private final IntBinaryOperator swapArrayCacheLambda = this::swapFunction_func_181674_a; + + protected int sortFunction_func_181674_a(int integer, int integer1) { + return Float.compare(sortArrayCacheA[sortArrayCacheB[integer1]], sortArrayCacheA[sortArrayCacheB[integer]]); + } + + protected int swapFunction_func_181674_a(int i, int j) { + int swap = sortArrayCacheB[i]; + sortArrayCacheB[i] = sortArrayCacheB[j]; + sortArrayCacheB[j] = swap; + return 0; + } + /** * MOST LIKELY USED TO SORT QUADS BACK TO FRONT */ public void func_181674_a(float parFloat1, float parFloat2, float parFloat3) { int i = this.vertexCount / 4; - final float[] afloat = new float[i]; + if(i == 0) { + return; + } + + float[] afloat = sortArrayCacheA; + if(afloat == null || afloat.length < i) { + afloat = new float[i]; + sortArrayCacheA = afloat; + } for (int j = 0; j < i; ++j) { afloat[j] = func_181665_a(this.floatBuffer, (float) ((double) parFloat1 + this.xOffset), @@ -97,30 +123,38 @@ public class WorldRenderer { this.vertexFormat.attribStride >> 2, j * this.vertexFormat.attribStride); } - Integer[] ainteger = new Integer[i]; - - for (int k = 0; k < ainteger.length; ++k) { - ainteger[k] = Integer.valueOf(k); + int[] ainteger = sortArrayCacheB; + if(ainteger == null || ainteger.length < i) { + ainteger = new int[i]; + sortArrayCacheB = ainteger; + } + + for (int k = 0; k < i; ++k) { + ainteger[k] = k; + } + + QuickSort.sort(0, i, sortArrayCacheLambda, swapArrayCacheLambda); + + BitSet bitset = sortBitSetCache; + if(bitset == null) { + bitset = new BitSet(); + sortBitSetCache = bitset; + }else { + bitset.clear(); } - Arrays.sort(ainteger, new Comparator() { - public int compare(Integer integer, Integer integer1) { - return Float.compare(afloat[integer1.intValue()], afloat[integer.intValue()]); - } - }); - BitSet bitset = new BitSet(); int l = this.vertexFormat.attribStride; int[] aint = new int[l]; - for (int l1 = 0; (l1 = bitset.nextClearBit(l1)) < ainteger.length; ++l1) { - int i1 = ainteger[l1].intValue(); + for (int l1 = 0; (l1 = bitset.nextClearBit(l1)) < i; ++l1) { + int i1 = ainteger[l1]; if (i1 != l1) { this.intBuffer.limit(i1 * l + l); this.intBuffer.position(i1 * l); this.intBuffer.get(aint); int j1 = i1; - for (int k1 = ainteger[i1].intValue(); j1 != l1; k1 = ainteger[k1].intValue()) { + for (int k1 = ainteger[i1]; j1 != l1; k1 = ainteger[k1]) { this.intBuffer.limit(k1 * l + l); this.intBuffer.position(k1 * l); IntBuffer intbuffer = this.intBuffer.duplicate(); diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/BlockVertexIDs.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/BlockVertexIDs.java index 5f6bcff1..7f8c1555 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/BlockVertexIDs.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/BlockVertexIDs.java @@ -3,8 +3,8 @@ package net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred; import java.io.BufferedReader; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; +import com.carrotsearch.hppc.ObjectIntHashMap; +import com.carrotsearch.hppc.ObjectIntMap; import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; import net.lax1dude.eaglercraft.v1_8.log4j.Logger; @@ -32,7 +32,7 @@ public class BlockVertexIDs implements IResourceManagerReloadListener { private static final Logger logger = LogManager.getLogger("BlockVertexIDsCSV"); - public static final Map modelToID = new HashMap<>(); + public static final ObjectIntMap modelToID = new ObjectIntHashMap<>(); public static int builtin_water_still_vertex_id = 0; public static int builtin_water_flow_vertex_id = 0; diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DebugFramebufferView.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DebugFramebufferView.java index 848208ed..28327d8a 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DebugFramebufferView.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DebugFramebufferView.java @@ -316,6 +316,14 @@ public class DebugFramebufferView { GlStateManager.bindTexture(pipeline.realisticWaterMaskTexture); DrawUtils.drawStandardQuad2D(); })), + (new DebugFramebufferView("Water: Combined Normals", (pipeline) -> { + if(!pipeline.config.is_rendering_realisticWater) throw new NoDataException(); + PipelineShaderGBufferDebugView dbv = pipeline.useDebugViewShader(1); + EaglerDeferredPipeline.uniformMatrixHelper(dbv.uniforms.u_inverseViewMatrix, DeferredStateManager.inverseViewMatrix); + GlStateManager.setActiveTexture(GL_TEXTURE0); + GlStateManager.bindTexture(pipeline.realisticWaterCombinedNormalsTexture); + DrawUtils.drawStandardQuad2D(); + })), (new DebugFramebufferView("Water: Surface Depth", (pipeline) -> { if(!pipeline.config.is_rendering_realisticWater) throw new NoDataException(); float depthStart = 0.001f; diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/EaglerDeferredPipeline.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/EaglerDeferredPipeline.java index fb4d71f8..dbea1ec5 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/EaglerDeferredPipeline.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/EaglerDeferredPipeline.java @@ -34,6 +34,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderP import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderRealisticWaterControl; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderRealisticWaterNoise; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderRealisticWaterNormalMap; +import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderRealisticWaterNormalsMix; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderReprojControl; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderReprojSSR; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderSSAOGenerate; @@ -43,6 +44,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderS import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderSkyboxRender; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderSkyboxRenderEnd; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderTonemap; +import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.ShaderMissingException; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.texture.MetalsLUT; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.texture.TemperaturesLUT; import net.lax1dude.eaglercraft.v1_8.vector.Matrix3f; @@ -291,6 +293,7 @@ public class EaglerDeferredPipeline { public PipelineShaderRealisticWaterControl shader_realistic_water_control = null; public PipelineShaderRealisticWaterNoise shader_realistic_water_noise = null; public PipelineShaderRealisticWaterNormalMap shader_realistic_water_normals = null; + public PipelineShaderRealisticWaterNormalsMix shader_realistic_water_normals_mix = null; public PipelineShaderHandDepthMask shader_hand_depth_mask = null; public PipelineShaderFXAA shader_post_fxaa = null; public SkyboxRenderer skybox = null; @@ -913,6 +916,12 @@ public class EaglerDeferredPipeline { shader_realistic_water_normals = PipelineShaderRealisticWaterNormalMap.compile(); shader_realistic_water_normals.loadUniforms(); _wglUniform2f(shader_realistic_water_normals.uniforms.u_sampleOffset2f, 0.00390625f, 0.00390625f); + try { + shader_realistic_water_normals_mix = PipelineShaderRealisticWaterNormalsMix.compile(); + shader_realistic_water_normals_mix.loadUniforms(); + }catch(ShaderMissingException exx) { + shader_realistic_water_normals_mix = null; + } if(!config.is_rendering_raytracing) { shader_reproject_ssr = PipelineShaderReprojSSR.compile(); shader_reproject_ssr.loadUniforms(); @@ -1083,7 +1092,7 @@ public class EaglerDeferredPipeline { double distX = worldX - reprojectionOriginCoordinateX; double distY = worldY - reprojectionOriginCoordinateY; double distZ = worldZ - reprojectionOriginCoordinateZ; - if(distX * distX + distY * distY + distZ * distZ > 48.0 * 48.0) { + if(distX * distX + distY * distY + distZ * distZ > 72.0 * 72.0) { reprojectionOriginCoordinateX = worldX; reprojectionOriginCoordinateY = worldY; reprojectionOriginCoordinateZ = worldZ; @@ -1098,7 +1107,7 @@ public class EaglerDeferredPipeline { } distX = worldX - cloudRenderOriginCoordinateX; distZ = worldZ - cloudRenderOriginCoordinateZ; - if(distX * distX + distZ * distZ > 256.0 * 256.0) { + if(distX * distX + distZ * distZ > 384.0 * 384.0) { cloudRenderOriginCoordinateX = worldX; cloudRenderOriginCoordinateZ = worldZ; cloudRenderViewerOffsetX = 0.0f; @@ -1844,39 +1853,44 @@ public class EaglerDeferredPipeline { _wglUniformMatrix4x2fv(shader_reproject_ssr.uniforms.u_lastInverseProjMatrix4x2f, false, matrixCopyBuffer); _wglUniform1f(shader_reproject_ssr.uniforms.u_sampleStep1f, 0.125f); - DrawUtils.drawStandardQuad2D(); // sample 1 + if(shader_reproject_ssr.uniforms.u_sampleDelta1i != null) { + _wglUniform1i(shader_reproject_ssr.uniforms.u_sampleDelta1i, 5); + DrawUtils.drawStandardQuad2D(); + }else { + DrawUtils.drawStandardQuad2D(); // sample 1 - _wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[0]); - GlStateManager.setActiveTexture(GL_TEXTURE3); - GlStateManager.bindTexture(reprojectionSSRHitVector[1]); - GlStateManager.setActiveTexture(GL_TEXTURE2); - GlStateManager.bindTexture(reprojectionSSRTexture[1]); + _wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[0]); + GlStateManager.setActiveTexture(GL_TEXTURE3); + GlStateManager.bindTexture(reprojectionSSRHitVector[1]); + GlStateManager.setActiveTexture(GL_TEXTURE2); + GlStateManager.bindTexture(reprojectionSSRTexture[1]); - DrawUtils.drawStandardQuad2D(); // sample 2 + DrawUtils.drawStandardQuad2D(); // sample 2 - _wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[1]); - GlStateManager.setActiveTexture(GL_TEXTURE3); - GlStateManager.bindTexture(reprojectionSSRHitVector[0]); - GlStateManager.setActiveTexture(GL_TEXTURE2); - GlStateManager.bindTexture(reprojectionSSRTexture[0]); + _wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[1]); + GlStateManager.setActiveTexture(GL_TEXTURE3); + GlStateManager.bindTexture(reprojectionSSRHitVector[0]); + GlStateManager.setActiveTexture(GL_TEXTURE2); + GlStateManager.bindTexture(reprojectionSSRTexture[0]); - DrawUtils.drawStandardQuad2D(); // sample 3 + DrawUtils.drawStandardQuad2D(); // sample 3 - _wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[0]); - GlStateManager.setActiveTexture(GL_TEXTURE3); - GlStateManager.bindTexture(reprojectionSSRHitVector[1]); - GlStateManager.setActiveTexture(GL_TEXTURE2); - GlStateManager.bindTexture(reprojectionSSRTexture[1]); + _wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[0]); + GlStateManager.setActiveTexture(GL_TEXTURE3); + GlStateManager.bindTexture(reprojectionSSRHitVector[1]); + GlStateManager.setActiveTexture(GL_TEXTURE2); + GlStateManager.bindTexture(reprojectionSSRTexture[1]); - DrawUtils.drawStandardQuad2D(); // sample 4 + DrawUtils.drawStandardQuad2D(); // sample 4 - _wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[1]); - GlStateManager.setActiveTexture(GL_TEXTURE3); - GlStateManager.bindTexture(reprojectionSSRHitVector[0]); - GlStateManager.setActiveTexture(GL_TEXTURE2); - GlStateManager.bindTexture(reprojectionSSRTexture[0]); + _wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[1]); + GlStateManager.setActiveTexture(GL_TEXTURE3); + GlStateManager.bindTexture(reprojectionSSRHitVector[0]); + GlStateManager.setActiveTexture(GL_TEXTURE2); + GlStateManager.bindTexture(reprojectionSSRTexture[0]); - DrawUtils.drawStandardQuad2D(); // sample 5 + DrawUtils.drawStandardQuad2D(); // sample 5 + } DeferredStateManager.checkGLError("combineGBuffersAndIlluminate(): RUN SCREENSPACE REFLECTIONS ALGORITHM"); } @@ -2663,14 +2677,24 @@ public class EaglerDeferredPipeline { _wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterCombinedNormalsFramebuffer); GlStateManager.viewport(0, 0, currentWidth, currentHeight); - GlStateManager.bindTexture(gBufferNormalsTexture); - TextureCopyUtil.blitTexture(); - - GlStateManager.bindTexture(realisticWaterMaskTexture); - GlStateManager.enableBlend(); - GlStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); - TextureCopyUtil.blitTexture(); - GlStateManager.disableBlend(); + if(shader_realistic_water_normals_mix != null) { + GlStateManager.disableBlend(); + GlStateManager.setActiveTexture(GL_TEXTURE1); + GlStateManager.bindTexture(realisticWaterMaskTexture); + GlStateManager.setActiveTexture(GL_TEXTURE0); + GlStateManager.bindTexture(gBufferNormalsTexture); + shader_realistic_water_normals_mix.useProgram(); + DrawUtils.drawStandardQuad2D(); + }else { + GlStateManager.bindTexture(gBufferNormalsTexture); + TextureCopyUtil.blitTexture(); + + GlStateManager.bindTexture(realisticWaterMaskTexture); + GlStateManager.enableBlend(); + GlStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); + TextureCopyUtil.blitTexture(); + GlStateManager.disableBlend(); + } DeferredStateManager.checkGLError("endDrawRealisticWaterMask(): COMBINE NORMALS"); @@ -2773,39 +2797,44 @@ public class EaglerDeferredPipeline { _wglUniformMatrix4x2fv(shader_reproject_ssr.uniforms.u_lastInverseProjMatrix4x2f, false, matrixCopyBuffer); _wglUniform1f(shader_reproject_ssr.uniforms.u_sampleStep1f, 0.5f); - DrawUtils.drawStandardQuad2D(); // sample 1 + if(shader_reproject_ssr.uniforms.u_sampleDelta1i != null) { + _wglUniform1i(shader_reproject_ssr.uniforms.u_sampleDelta1i, 5); + DrawUtils.drawStandardQuad2D(); + }else { + DrawUtils.drawStandardQuad2D(); // sample 1 - _wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[0]); - GlStateManager.setActiveTexture(GL_TEXTURE3); - GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[1]); - GlStateManager.setActiveTexture(GL_TEXTURE2); - GlStateManager.bindTexture(realisticWaterControlReflectionTexture[1]); + _wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[0]); + GlStateManager.setActiveTexture(GL_TEXTURE3); + GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[1]); + GlStateManager.setActiveTexture(GL_TEXTURE2); + GlStateManager.bindTexture(realisticWaterControlReflectionTexture[1]); - DrawUtils.drawStandardQuad2D(); // sample 2 + DrawUtils.drawStandardQuad2D(); // sample 2 - _wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[1]); - GlStateManager.setActiveTexture(GL_TEXTURE3); - GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[0]); - GlStateManager.setActiveTexture(GL_TEXTURE2); - GlStateManager.bindTexture(realisticWaterControlReflectionTexture[0]); + _wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[1]); + GlStateManager.setActiveTexture(GL_TEXTURE3); + GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[0]); + GlStateManager.setActiveTexture(GL_TEXTURE2); + GlStateManager.bindTexture(realisticWaterControlReflectionTexture[0]); - DrawUtils.drawStandardQuad2D(); // sample 3 + DrawUtils.drawStandardQuad2D(); // sample 3 - _wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[0]); - GlStateManager.setActiveTexture(GL_TEXTURE3); - GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[1]); - GlStateManager.setActiveTexture(GL_TEXTURE2); - GlStateManager.bindTexture(realisticWaterControlReflectionTexture[1]); + _wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[0]); + GlStateManager.setActiveTexture(GL_TEXTURE3); + GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[1]); + GlStateManager.setActiveTexture(GL_TEXTURE2); + GlStateManager.bindTexture(realisticWaterControlReflectionTexture[1]); - DrawUtils.drawStandardQuad2D(); // sample 4 + DrawUtils.drawStandardQuad2D(); // sample 4 - _wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[1]); - GlStateManager.setActiveTexture(GL_TEXTURE3); - GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[0]); - GlStateManager.setActiveTexture(GL_TEXTURE2); - GlStateManager.bindTexture(realisticWaterControlReflectionTexture[0]); + _wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[1]); + GlStateManager.setActiveTexture(GL_TEXTURE3); + GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[0]); + GlStateManager.setActiveTexture(GL_TEXTURE2); + GlStateManager.bindTexture(realisticWaterControlReflectionTexture[0]); - DrawUtils.drawStandardQuad2D(); // sample 5 + DrawUtils.drawStandardQuad2D(); // sample 5 + } DeferredStateManager.checkGLError("endDrawRealisticWaterMask(): RUN SCREENSPACE REFLECTIONS ALGORITHM"); @@ -3066,6 +3095,8 @@ public class EaglerDeferredPipeline { GlStateManager.clear(GL_DEPTH_BUFFER_BIT); GlStateManager.enableDepth(); DeferredStateManager.setDefaultMaterialConstants(); + DeferredStateManager.disableFog(); + updateForwardRenderWorldLightingData(); DeferredStateManager.checkGLError("Post: beginDrawHandOverlay()"); } @@ -3838,6 +3869,10 @@ public class EaglerDeferredPipeline { shader_realistic_water_normals.destroy(); shader_realistic_water_normals = null; } + if(shader_realistic_water_normals_mix != null) { + shader_realistic_water_normals_mix.destroy(); + shader_realistic_water_normals_mix = null; + } if(shader_post_fxaa != null) { shader_post_fxaa.destroy(); shader_post_fxaa = null; diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderRealisticWaterNormalsMix.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderRealisticWaterNormalsMix.java new file mode 100755 index 00000000..ed2ceb85 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderRealisticWaterNormalsMix.java @@ -0,0 +1,57 @@ +package net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program; + +import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*; +import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; + +import net.lax1dude.eaglercraft.v1_8.internal.IProgramGL; +import net.lax1dude.eaglercraft.v1_8.internal.IShaderGL; + +/** + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class PipelineShaderRealisticWaterNormalsMix extends ShaderProgram { + + public static PipelineShaderRealisticWaterNormalsMix compile() throws ShaderException { + IShaderGL normalsMix = ShaderCompiler.compileShader("realistic_water_normals_mix", GL_FRAGMENT_SHADER, + ShaderSource.realistic_water_normals_mix_fsh); + try { + IProgramGL prog = ShaderCompiler.linkProgram("realistic_water_normals_mix", + SharedPipelineShaders.deferred_local, normalsMix); + return new PipelineShaderRealisticWaterNormalsMix(prog); + }finally { + if(normalsMix != null) { + normalsMix.free(); + } + } + } + + private PipelineShaderRealisticWaterNormalsMix(IProgramGL program) { + super(program, new Uniforms()); + } + + public static class Uniforms implements IProgramUniforms { + + private Uniforms() { + } + + @Override + public void loadUniforms(IProgramGL prog) { + _wglUniform1i(_wglGetUniformLocation(prog, "u_gbufferNormalsTexture"), 0); + _wglUniform1i(_wglGetUniformLocation(prog, "u_surfaceNormalsTexture"), 1); + } + + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderReprojSSR.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderReprojSSR.java index 41c0cf98..4b7a90f0 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderReprojSSR.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderReprojSSR.java @@ -48,6 +48,7 @@ public class PipelineShaderReprojSSR extends ShaderProgram compileFlags) throws ShaderCompileException { - return compileShader(name, stage, filename.toString(), ShaderSource.getSourceFor(filename), compileFlags); + String src = ShaderSource.getSourceFor(filename); + if(src == null) { + throw new ShaderMissingException(name, "File not found: " + filename); + } + return compileShader(name, stage, filename.toString(), src, compileFlags); } public static IShaderGL compileShader(String name, int stage, String filename, String source, List compileFlags) throws ShaderCompileException { diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderMissingException.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderMissingException.java new file mode 100755 index 00000000..b76437f1 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderMissingException.java @@ -0,0 +1,24 @@ +package net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program; + +/** + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class ShaderMissingException extends ShaderException { + + public ShaderMissingException(String shaderName, String msg) { + super(shaderName, msg); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderSource.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderSource.java index c0fa936c..b89d9bde 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderSource.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderSource.java @@ -54,6 +54,7 @@ public class ShaderSource { public static final ResourceLocation realistic_water_render_fsh = new ResourceLocation("eagler:glsl/deferred/realistic_water_render.fsh"); public static final ResourceLocation realistic_water_control_fsh = new ResourceLocation("eagler:glsl/deferred/realistic_water_control.fsh"); public static final ResourceLocation realistic_water_normals_fsh = new ResourceLocation("eagler:glsl/deferred/realistic_water_normals.fsh"); + public static final ResourceLocation realistic_water_normals_mix_fsh = new ResourceLocation("eagler:glsl/deferred/realistic_water_normals_mix.fsh"); public static final ResourceLocation realistic_water_noise_fsh = new ResourceLocation("eagler:glsl/deferred/realistic_water_noise.fsh"); public static final ResourceLocation gbuffer_debug_view_fsh = new ResourceLocation("eagler:glsl/deferred/gbuffer_debug_view.fsh"); public static final ResourceLocation ssao_generate_fsh = new ResourceLocation("eagler:glsl/deferred/ssao_generate.fsh"); diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/EaglerTextureAtlasSpritePBR.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/EaglerTextureAtlasSpritePBR.java index 9032dfd6..d481ee4e 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/EaglerTextureAtlasSpritePBR.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/EaglerTextureAtlasSpritePBR.java @@ -1,10 +1,10 @@ package net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.texture; import java.io.IOException; -import java.util.Iterator; import java.util.List; import java.util.concurrent.Callable; +import com.carrotsearch.hppc.cursors.IntCursor; import com.google.common.collect.Lists; import net.lax1dude.eaglercraft.v1_8.HString; @@ -104,10 +104,8 @@ public class EaglerTextureAtlasSpritePBR extends EaglerTextureAtlasSprite { int l = i; this.height = this.width; if (meta.getFrameCount() > 0) { - Iterator iterator = meta.getFrameIndexSet().iterator(); - - while (iterator.hasNext()) { - int i1 = ((Integer) iterator.next()).intValue(); + for (IntCursor cur : meta.getFrameIndexSet()) { + int i1 = cur.value; if (i1 >= j1) { throw new RuntimeException("invalid frameindex " + i1); } diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerSkinCache.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerSkinCache.java index b98622cf..f996858c 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerSkinCache.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerSkinCache.java @@ -201,7 +201,7 @@ public class ServerSkinCache { } public SkinCacheEntry getSkin(String url, SkinModel skinModelResponse) { - if(url.length() > 0xFFFF) { + if(url.length() > 0x7F00) { return skinModelResponse == SkinModel.ALEX ? defaultSlimCacheEntry : defaultCacheEntry; } EaglercraftUUID generatedUUID = SkinPackets.createEaglerURLSkinUUID(url); diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/socket/ServerQueryImpl.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/socket/ServerQueryImpl.java index a9b2047a..6b22ba14 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/socket/ServerQueryImpl.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/socket/ServerQueryImpl.java @@ -10,7 +10,6 @@ import net.lax1dude.eaglercraft.v1_8.internal.EnumServerRateLimit; import net.lax1dude.eaglercraft.v1_8.internal.IServerQuery; import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketClient; import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame; -import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime; import net.lax1dude.eaglercraft.v1_8.internal.QueryResponse; import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; import net.lax1dude.eaglercraft.v1_8.log4j.Logger; diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/GameProtocolMessageController.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/GameProtocolMessageController.java index 56e5fd63..ccf4bf6f 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/GameProtocolMessageController.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/GameProtocolMessageController.java @@ -1,6 +1,7 @@ package net.lax1dude.eaglercraft.v1_8.socket.protocol.client; import java.io.IOException; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -149,10 +150,12 @@ public class GameProtocolMessageController { while(sendQueueV4.size() > 0) { sendCount = 0; totalLen = 0; + Iterator itr = sendQueueV4.iterator(); do { - i = sendQueueV4.get(sendCount++).readableBytes(); + i = itr.next().readableBytes(); totalLen += GamePacketOutputBuffer.getVarIntSize(i) + i; - }while(totalLen < 32760 && sendCount < sendQueueV4.size()); + ++sendCount; + }while(totalLen < 32760 && itr.hasNext()); if(totalLen >= 32760) { --sendCount; } diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacketManager.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacketManager.java index 96080f10..d56c248d 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacketManager.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacketManager.java @@ -3,9 +3,11 @@ package net.lax1dude.eaglercraft.v1_8.sp.ipc; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.util.HashMap; import java.util.function.Supplier; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; + /** * Copyright (c) 2023-2024 lax1dude. All Rights Reserved. * @@ -23,7 +25,7 @@ import java.util.function.Supplier; */ public class IPCPacketManager { - public static final HashMap> mappings = new HashMap<>(); + public static final IntObjectMap> mappings = new IntObjectHashMap<>(); public final IPCInputStream IPC_INPUT_STREAM = new IPCInputStream(); public final IPCOutputStream IPC_OUTPUT_STREAM = new IPCOutputStream(); diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientNetworkManager.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientNetworkManager.java index 777f754a..8cb99607 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientNetworkManager.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientNetworkManager.java @@ -2,9 +2,7 @@ package net.lax1dude.eaglercraft.v1_8.sp.lan; import net.lax1dude.eaglercraft.v1_8.EagRuntime; import net.lax1dude.eaglercraft.v1_8.EagUtils; -import net.lax1dude.eaglercraft.v1_8.EaglerInputStream; import net.lax1dude.eaglercraft.v1_8.EaglerZLIB; -import net.lax1dude.eaglercraft.v1_8.IOUtils; import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState; import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC; import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; @@ -21,7 +19,6 @@ import net.minecraft.util.ChatComponentTranslation; import net.minecraft.util.IChatComponent; import java.io.IOException; -import java.io.InputStream; import java.util.ArrayList; import java.util.List; @@ -308,13 +305,26 @@ public class LANClientNetworkManager extends EaglercraftNetworkManager { } for(int k = 0, l = packets.size(); k < l; ++k) { byte[] data = packets.get(k); + + if(firstPacket) { + // 1.5 kick packet + if(data.length == 31 && data[0] == (byte)0xFF && data[1] == (byte)0x00 && data[2] == (byte)0x0E) { + logger.error("Detected a 1.5 LAN server!"); + this.closeChannel(new ChatComponentTranslation("singleplayer.outdatedLANServerKick")); + firstPacket = false; + return; + } + firstPacket = false; + } + byte[] fullData; boolean compressed = false; + int off = 0; if (data[0] == 0 || data[0] == 2) { if(fragmentedPacket.isEmpty()) { - fullData = new byte[data.length - 1]; - System.arraycopy(data, 1, fullData, 0, fullData.length); + fullData = data; + off = 1; }else { fragmentedPacket.add(data); int len = 0; @@ -341,34 +351,23 @@ public class LANClientNetworkManager extends EaglercraftNetworkManager { } if(compressed) { - if(fullData.length < 4) { + if(fullData.length < 4 + off) { throw new IOException("Recieved invalid " + fullData.length + " byte compressed packet"); } - EaglerInputStream bi = new EaglerInputStream(fullData); - int i = (bi.read() << 24) | (bi.read() << 16) | (bi.read() << 8) | bi.read(); - fullData = new byte[i]; - int r; - try(InputStream inflaterInputStream = EaglerZLIB.newInflaterInputStream(bi)) { - r = IOUtils.readFully(inflaterInputStream, fullData); - } + int i = (((int) fullData[off] & 0xFF) << 24) | (((int) fullData[off + 1] & 0xFF) << 16) + | (((int) fullData[off + 2] & 0xFF) << 8) | ((int) fullData[off + 3] & 0xFF); + byte[] fullData2 = new byte[i]; + int r = EaglerZLIB.inflateFull(fullData, off + 4, fullData.length - off - 4, fullData2, 0, i); + fullData = fullData2; + off = 0; if (i != r) { logger.warn("Decompressed packet expected size {} differs from actual size {}!", i, r); } } - if(firstPacket) { - // 1.5 kick packet - if(fullData.length == 31 && fullData[0] == (byte)0xFF && fullData[1] == (byte)0x00 && fullData[2] == (byte)0x0E) { - logger.error("Detected a 1.5 LAN server!"); - this.closeChannel(new ChatComponentTranslation("singleplayer.outdatedLANServerKick")); - firstPacket = false; - return; - } - firstPacket = false; - } - ByteBuf nettyBuffer = Unpooled.buffer(fullData, fullData.length); nettyBuffer.writerIndex(fullData.length); + nettyBuffer.readerIndex(off); PacketBuffer input = new PacketBuffer(nettyBuffer); int pktId = input.readVarIntFromBuffer(); diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/GenLayerEaglerRivers.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/GenLayerEaglerRivers.java new file mode 100755 index 00000000..81946edc --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/GenLayerEaglerRivers.java @@ -0,0 +1,107 @@ +package net.lax1dude.eaglercraft.v1_8.sp.server; + +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraft.world.gen.layer.GenLayer; +import net.minecraft.world.gen.layer.IntCache; + +/** + * Copyright (c) 2025 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class GenLayerEaglerRivers extends GenLayer { + + private static final int[] pattern = new int[] { + 0b111000011100001110000111, + 0b111000111110011111000111, + 0b011100011100001110001110, + 0b011100000000000000001110, + 0b001110000000000000011100, + 0b001110000000000000011100, + 0b000111000000000000111000, + 0b000111000000000000111000, + 0b000011100000000001110000, + 0b000011100000000001110000, + 0b000001110000000011100000, + 0b000001110000000011100000, + 0b000000111000000111000000, + 0b000000111000000111000000, + 0b000000011100001110000000, + 0b000000011100001110000000, + 0b000000001110011100000000, + 0b000000001110011100000000, + 0b000000000111111000000000, + 0b000000000111111000000000, + 0b000000000011110000000000, + 0b000000000011110000000000, + 0b000000000001100000000000, + 0b000000000001100000000000, + }; + + private static final int patternSize = 24; + + public GenLayerEaglerRivers(long parLong1, GenLayer p) { + super(parLong1); + this.parent = p; + } + + @Override + public int[] getInts(int x, int y, int w, int h) { + int[] aint = this.parent.getInts(x, y, w, h); + int[] aint1 = IntCache.getIntCache(w * h); + + long a = worldGenSeed * 6364136223846793005L + 1442695040888963407L; + long b = ((a & 112104l) == 0) ? (((a & 534l) == 0) ? 1l : 15l) : 746l; + for (int yy = 0; yy < h; ++yy) { + for (int xx = 0; xx < w; ++xx) { + int i = xx + yy * w; + aint1[i] = aint[i]; + long xxx = (long)(x + xx) & 0xFFFFFFFFl; + long yyy = (long)(y + yy) & 0xFFFFFFFFl; + long hash = a + (xxx / patternSize); + hash *= hash * 6364136223846793005L + 1442695040888963407L; + hash += (yyy / patternSize); + hash *= hash * 6364136223846793005L + 1442695040888963407L; + hash += a; + if ((hash & b) == 0l) { + xxx %= (long)patternSize; + yyy %= (long)patternSize; + long tmp; + switch((int)((hash >>> 16l) & 3l)) { + case 1: + tmp = xxx; + xxx = yyy; + yyy = (long)patternSize - tmp - 1l; + break; + case 2: + tmp = xxx; + xxx = (long)patternSize - yyy - 1l; + yyy = tmp; + break; + case 3: + tmp = xxx; + xxx = (long)patternSize - yyy - 1l; + yyy = (long)patternSize - tmp - 1l; + break; + } + if((pattern[(int)yyy] & (1 << (int)xxx)) != 0) { + aint1[i] = BiomeGenBase.river.biomeID; + } + } + } + } + + return aint1; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/IntegratedServerPlayerNetworkManager.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/IntegratedServerPlayerNetworkManager.java index eee0b86a..56e58f7f 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/IntegratedServerPlayerNetworkManager.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/IntegratedServerPlayerNetworkManager.java @@ -2,8 +2,8 @@ package net.lax1dude.eaglercraft.v1_8.sp.server.socket; import java.io.DataOutputStream; import java.io.IOException; -import java.io.OutputStream; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; import net.lax1dude.eaglercraft.v1_8.EaglerOutputStream; @@ -48,10 +48,9 @@ public class IntegratedServerPlayerNetworkManager { public final String playerChannel; private EnumConnectionState packetState = EnumConnectionState.HANDSHAKING; private static PacketBuffer temporaryBuffer; - private static EaglerOutputStream temporaryOutputStream; + private static byte[] compressedPacketTmp; private int debugPacketCounter = 0; - private byte[][] recievedPacketBuffer = new byte[16384][]; - private int recievedPacketBufferCounter = 0; + private final List recievedPacketBuffer = new LinkedList<>(); private final boolean enableSendCompression; private boolean firstPacket = true; @@ -69,11 +68,6 @@ public class IntegratedServerPlayerNetworkManager { } this.playerChannel = playerChannel; this.enableSendCompression = !SingleplayerServerController.PLAYER_CHANNEL.equals(playerChannel); - if(this.enableSendCompression) { - if(temporaryOutputStream == null) { - temporaryOutputStream = new EaglerOutputStream(16386); - } - } } public void connect() { @@ -97,19 +91,14 @@ public class IntegratedServerPlayerNetworkManager { } public void addRecievedPacket(byte[] next) { - if(recievedPacketBufferCounter < recievedPacketBuffer.length - 1) { - recievedPacketBuffer[recievedPacketBufferCounter++] = next; - }else { - logger.error("Dropping packets on recievedPacketBuffer for channel \"{}\"! (overflow)", playerChannel); - } + recievedPacketBuffer.add(next); } public void processReceivedPackets() { if(nethandler == null) return; - - for(int i = 0; i < recievedPacketBufferCounter; ++i) { - byte[] data = recievedPacketBuffer[i]; + while(!recievedPacketBuffer.isEmpty()) { + byte[] data = recievedPacketBuffer.remove(0); byte[] fullData; if(enableSendCompression) { @@ -132,7 +121,6 @@ public class IntegratedServerPlayerNetworkManager { ServerPlatformSingleplayer.sendPacket(new IPCPacketData(playerChannel, kickPacketBAO.toByteArray())); closeChannel(new ChatComponentText("Recieved unsuppoorted connection from an Eaglercraft 1.5.2 client!")); firstPacket = false; - recievedPacketBufferCounter = 0; return; } firstPacket = false; @@ -169,7 +157,6 @@ public class IntegratedServerPlayerNetworkManager { fullData = data; } - recievedPacketBuffer[i] = null; ++debugPacketCounter; try { ByteBuf nettyBuffer = Unpooled.buffer(fullData, fullData.length); @@ -206,7 +193,6 @@ public class IntegratedServerPlayerNetworkManager { logger.error(t); } } - recievedPacketBufferCounter = 0; } public void sendPacket(Packet pkt) { @@ -234,22 +220,24 @@ public class IntegratedServerPlayerNetworkManager { int len = temporaryBuffer.readableBytes(); if(enableSendCompression) { if(len > compressionThreshold) { - temporaryOutputStream.reset(); - byte[] compressedData; + if(compressedPacketTmp == null || compressedPacketTmp.length < len) { + compressedPacketTmp = new byte[len]; + } + int cmpLen; try { - temporaryOutputStream.write(2); - temporaryOutputStream.write((len >>> 24) & 0xFF); - temporaryOutputStream.write((len >>> 16) & 0xFF); - temporaryOutputStream.write((len >>> 8) & 0xFF); - temporaryOutputStream.write(len & 0xFF); - try(OutputStream os = EaglerZLIB.newDeflaterOutputStream(temporaryOutputStream)) { - temporaryBuffer.readBytes(os, len); - } - compressedData = temporaryOutputStream.toByteArray(); + cmpLen = EaglerZLIB.deflateFull(temporaryBuffer.array(), 0, len, compressedPacketTmp, 0, compressedPacketTmp.length); }catch(IOException ex) { logger.error("Failed to compress packet {}!", pkt.getClass().getSimpleName()); + logger.error(ex); return; } + byte[] compressedData = new byte[5 + cmpLen]; + compressedData[0] = (byte)2; + compressedData[1] = (byte)((len >>> 24) & 0xFF); + compressedData[2] = (byte)((len >>> 16) & 0xFF); + compressedData[3] = (byte)((len >>> 8) & 0xFF); + compressedData[4] = (byte)(len & 0xFF); + System.arraycopy(compressedPacketTmp, 0, compressedData, 5, cmpLen); if(compressedData.length > fragmentSize) { int fragmentSizeN1 = fragmentSize - 1; for (int j = 1; j < compressedData.length; j += fragmentSizeN1) { diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/ClientIntegratedServerNetworkManager.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/ClientIntegratedServerNetworkManager.java index b5373d39..c9267607 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/ClientIntegratedServerNetworkManager.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/ClientIntegratedServerNetworkManager.java @@ -1,6 +1,8 @@ package net.lax1dude.eaglercraft.v1_8.sp.socket; import java.io.IOException; +import java.util.LinkedList; +import java.util.List; import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState; import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData; @@ -34,8 +36,7 @@ import net.minecraft.util.IChatComponent; public class ClientIntegratedServerNetworkManager extends EaglercraftNetworkManager { private int debugPacketCounter = 0; - private byte[][] recievedPacketBuffer = new byte[16384][]; - private int recievedPacketBufferCounter = 0; + private final List recievedPacketBuffer = new LinkedList<>(); public boolean isPlayerChannelOpen = false; public ClientIntegratedServerNetworkManager(String channel) { @@ -65,20 +66,15 @@ public class ClientIntegratedServerNetworkManager extends EaglercraftNetworkMana } public void addRecievedPacket(byte[] next) { - if(recievedPacketBufferCounter < recievedPacketBuffer.length - 1) { - recievedPacketBuffer[recievedPacketBufferCounter++] = next; - }else { - logger.error("Dropping packets on recievedPacketBuffer for channel \"{}\"! (overflow)", address); - } + recievedPacketBuffer.add(next); } @Override public void processReceivedPackets() throws IOException { if(nethandler == null) return; - for(int i = 0; i < recievedPacketBufferCounter; ++i) { - byte[] next = recievedPacketBuffer[i]; - recievedPacketBuffer[i] = null; + while(!recievedPacketBuffer.isEmpty()) { + byte[] next = recievedPacketBuffer.remove(0); ++debugPacketCounter; try { ByteBuf nettyBuffer = Unpooled.buffer(next, next.length); @@ -115,7 +111,6 @@ public class ClientIntegratedServerNetworkManager extends EaglercraftNetworkMana logger.error(t); } } - recievedPacketBufferCounter = 0; } @Override @@ -170,9 +165,6 @@ public class ClientIntegratedServerNetworkManager extends EaglercraftNetworkMana } public void clearRecieveQueue() { - for(int i = 0; i < recievedPacketBufferCounter; ++i) { - recievedPacketBuffer[i] = null; - } - recievedPacketBufferCounter = 0; + recievedPacketBuffer.clear(); } } diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchControls.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchControls.java index 94bbaa58..587f8eb1 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchControls.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchControls.java @@ -7,6 +7,10 @@ import net.minecraft.client.gui.ScaledResolution; import java.util.*; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; +import com.carrotsearch.hppc.cursors.ObjectCursor; + /** * Copyright (c) 2024 lax1dude, ayunami2000. All Rights Reserved. * @@ -24,7 +28,7 @@ import java.util.*; */ public class TouchControls { - public static final Map touchControls = new HashMap<>(); + public static final IntObjectMap touchControls = new IntObjectHashMap<>(); protected static Set touchControlPressed = EnumSet.noneOf(EnumTouchControl.class); protected static boolean isSneakToggled = false; @@ -112,7 +116,8 @@ public class TouchControls { if(!touchControls.isEmpty()) { Set newPressed = EnumSet.noneOf(EnumTouchControl.class); TouchOverlayRenderer renderer = Minecraft.getMinecraft().touchOverlayRenderer; - for (TouchControlInput input : touchControls.values()) { + for (ObjectCursor input_ : touchControls.values()) { + TouchControlInput input = input_.value; TouchAction action = input.control.getAction(); if(action != null) { action.call(input.control, input.x, input.y); diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchOverlayRenderer.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchOverlayRenderer.java index 663196c7..edb12677 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchOverlayRenderer.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchOverlayRenderer.java @@ -17,6 +17,7 @@ import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; import java.util.Set; +import com.carrotsearch.hppc.cursors.ObjectCursor; import com.google.common.collect.Sets; /** @@ -103,8 +104,8 @@ public class TouchOverlayRenderer { GlStateManager.clear(GL_COLOR_BUFFER_BIT); } Set controls = Sets.newHashSet(EnumTouchControl._VALUES); - for (TouchControlInput input : TouchControls.touchControls.values()) { - controls.remove(input.control); + for (ObjectCursor input : TouchControls.touchControls.values()) { + controls.remove(input.value.control); } for (EnumTouchControl control : controls) { if(invalidDeep || control.invalid) { @@ -115,7 +116,8 @@ public class TouchOverlayRenderer { control.invalid = false; } } - for (TouchControlInput input : TouchControls.touchControls.values()) { + for (ObjectCursor input_ : TouchControls.touchControls.values()) { + TouchControlInput input = input_.value; EnumTouchControl control = input.control; if(invalidDeep || control.invalid) { if(control.visible) { diff --git a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java index 628ee0ba..9b0f996c 100755 --- a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java +++ b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java @@ -42,9 +42,11 @@ import org.teavm.platform.PlatformRunnable; import com.google.common.collect.Collections2; import com.google.common.collect.Iterators; import com.google.common.collect.Sets; +import com.jcraft.jzlib.Deflater; import com.jcraft.jzlib.DeflaterOutputStream; import com.jcraft.jzlib.GZIPInputStream; import com.jcraft.jzlib.GZIPOutputStream; +import com.jcraft.jzlib.Inflater; import com.jcraft.jzlib.InflaterInputStream; import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer; @@ -539,11 +541,21 @@ public class PlatformRuntime { } public static String getGLVersion() { - return PlatformOpenGL._wglGetString(RealOpenGLEnums.GL_VERSION); + String ret = PlatformOpenGL._wglGetString(RealOpenGLEnums.GL_VERSION); + if(ret != null) { + return ret; + }else { + return "null"; + } } public static String getGLRenderer() { - return PlatformOpenGL._wglGetString(RealOpenGLEnums.GL_RENDERER); + String ret = PlatformOpenGL._wglGetString(RealOpenGLEnums.GL_RENDERER); + if(ret != null) { + return ret; + }else { + return "null"; + } } public static ByteBuffer allocateByteBuffer(int length) { @@ -1070,6 +1082,23 @@ public class PlatformRuntime { return new DeflaterOutputStream(os); } + @SuppressWarnings("deprecation") + public static int deflateFull(byte[] input, int inputOff, int inputLen, byte[] output, int outputOff, + int outputLen) throws IOException { + Deflater df = new Deflater(); + df.setInput(input, inputOff, inputLen, false); + df.setOutput(output, outputOff, outputLen); + df.init(5); + int c; + do { + c = df.deflate(4); + if(c != 0 && c != 1) { + throw new IOException("Deflater failed! Code " + c); + } + }while(c != 1); + return (int)df.getTotalOut(); + } + public static OutputStream newGZIPOutputStream(OutputStream os) throws IOException { return new GZIPOutputStream(os); } @@ -1078,6 +1107,22 @@ public class PlatformRuntime { return new InflaterInputStream(is); } + @SuppressWarnings("deprecation") + public static int inflateFull(byte[] input, int inputOff, int inputLen, byte[] output, int outputOff, + int outputLen) throws IOException { + Inflater df = new Inflater(); + df.setInput(input, inputOff, inputLen, false); + df.setOutput(output, outputOff, outputLen); + int c; + do { + c = df.inflate(0); + if(c != 0 && c != 1) { + throw new IOException("Inflater failed! Code " + c); + } + }while(c != 1); + return (int)df.getTotalOut(); + } + public static InputStream newGZIPInputStream(InputStream is) throws IOException { return new GZIPInputStream(is); } diff --git a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayByteBuffer.java b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayByteBuffer.java index c3d37a0d..6aa6e497 100755 --- a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayByteBuffer.java +++ b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayByteBuffer.java @@ -9,7 +9,7 @@ import org.teavm.jso.typedarrays.Int8Array; import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils; /** - * Copyright (c) 2022-2023 lax1dude. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -23,7 +23,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils; * POSSIBILITY OF SUCH DAMAGE. * */ -public class EaglerArrayByteBuffer implements ByteBuffer { +public class EaglerArrayByteBuffer extends ByteBuffer { final DataView dataView; final Int8Array typedArray; diff --git a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayFloatBuffer.java b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayFloatBuffer.java index b94ee42f..68ce9211 100755 --- a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayFloatBuffer.java +++ b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayFloatBuffer.java @@ -5,7 +5,7 @@ import org.teavm.jso.typedarrays.Float32Array; import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils; /** - * Copyright (c) 2022-2023 lax1dude. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -19,7 +19,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils; * POSSIBILITY OF SUCH DAMAGE. * */ -public class EaglerArrayFloatBuffer implements FloatBuffer { +public class EaglerArrayFloatBuffer extends FloatBuffer { final Float32Array typedArray; diff --git a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayIntBuffer.java b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayIntBuffer.java index 85cb3f44..5a4f2019 100755 --- a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayIntBuffer.java +++ b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayIntBuffer.java @@ -5,7 +5,7 @@ import org.teavm.jso.typedarrays.Int32Array; import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils; /** - * Copyright (c) 2022-2023 lax1dude. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -19,7 +19,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils; * POSSIBILITY OF SUCH DAMAGE. * */ -public class EaglerArrayIntBuffer implements IntBuffer { +public class EaglerArrayIntBuffer extends IntBuffer { final Int32Array typedArray; diff --git a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayShortBuffer.java b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayShortBuffer.java index d83b9a7c..e7e4e12e 100755 --- a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayShortBuffer.java +++ b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayShortBuffer.java @@ -5,7 +5,7 @@ import org.teavm.jso.typedarrays.Int16Array; import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils; /** - * Copyright (c) 2022-2023 lax1dude. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -19,7 +19,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils; * POSSIBILITY OF SUCH DAMAGE. * */ -public class EaglerArrayShortBuffer implements ShortBuffer { +public class EaglerArrayShortBuffer extends ShortBuffer { final Int16Array typedArray; diff --git a/src/wasm-gc-teavm-bootstrap/js/main.js b/src/wasm-gc-teavm-bootstrap/js/main.js index fd577594..8aaccc34 100755 --- a/src/wasm-gc-teavm-bootstrap/js/main.js +++ b/src/wasm-gc-teavm-bootstrap/js/main.js @@ -133,6 +133,24 @@ function asyncSleep(ms) { }); } +/** + * @param {string} url + * @param {number} ms + * @return {!Promise} + */ +function preloadImage(url, ms) { + return new Promise(function(resolve) { + const imgObj = new Image(); + imgObj.addEventListener("load", resolve); + imgObj.addEventListener("error", function() { + logWarn("Failed to preload image: " + url); + resolve(); + }); + imgObj.src = url; + setTimeout(resolve, ms); + }); +} + /** * @param {string} url * @return {!Promise} @@ -248,6 +266,9 @@ window.main = async function() { splashElement.style.background = "center / contain no-repeat url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAAAAAB3tzPbAAAACXBIWXMAAC4jAAAuIwF4pT92AAAG+UlEQVR42u2cy23jOhRATwbTwGwFvAJoF6BFGjColcGkASNuIPA6C68DN+BADZiCVxLSQBYqIGYBAbSdEvwWkvUzZWfymwlwCQwQUZeXPOT9URPkYs/3bj8QAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAH4x9vPvzFpAhAzM98UILmqfjDf1YT0N/cBk+71v+wDSczHmDeJ6TqO+SIfyD7IvC9g33Yc7dP6CQDxB+q62Hc2xnyJD2Sf5vuzL3Hi5MM0WbCN51u/Y/30ryEGmDVHlhwsY9Y7xlq0CuzVc4lh2n7NkGsnQ1nB7IefmrY/araJcbrq6Ryk9YqW4l3J/dHww1jdej+8kte042EW0Nba1hyWdl+9irq/FNXaD6BbQoexuvf+tQC2vX1+AFvP0kxiuyidfWwEbOtQtK0n0r6xbYCKsLcM21+pLZX3u4984Kq2xlnWDimllRudAXEpkGSHfqMzsmxfWnLWNf9aQznW4wMZWOMJxvGs/Ff5X+yPcD0g3dqZesdsI2f7Z2/73W2JSok9Gqu7P1q/I2qtj0qn/ZkTaCPWO2a0VyjrxY7sNUG1LxRlaE90MpDpGVeAxpaGobN2XPWH0aQVE1stfXPAj0+XzUmcob3aTRdVZ2+tRv+gMNBDaTkZ4k6uhtYPaK7iUkUcx9lgij92gZ6aXmxoDeK8D1hPfm18oBvTfPGwXoVG+4VfXcwl8dEOtCJS7De9M0VTqTA2p081O3kJ+uk5cU/RVN8C262Ms9HMlLHSmhNFTcc9u1uQRX4jMhqyNIk1GRk69a6hb0IDZ3pITnbfNqFuJWE9gbYrfmSqen/SiKy27G0VS20VWc+UEn59/YDPkc+0EunrAXQ/JXucYL+3VutyAqvP5wFvtEoyQPsMJMpKc3v7/Su9ALLkhAJDPCObGTDmonfNHAij3sg5866fmTHGnFt/crroh6vEv/Rq6vhEoP7hWWb2ylSQZP5zOVrDqVxSZnm/xL6OFnZwF3/4JoyGjyXu1X3n0rEFyE5Jzc5KEDfT7s2ZYs52s5e1HU88hB17nKTqAroXWPpXiHbN7R3Q8fVDbjzU6vb8hUbX67FWN8Xo4U5SIWjbukr1knY9XrcwS30aOuTatqa0vkA6cI05dyPrzWBbj7ZZrPUT2O7pdpKFtp4rph0E0AxtfN0u9kNVg25d4BPiDF0+R83dPol7/l4m4yQmQzdX+ISewqTnc8ngp94yaCan4vT+Hc228q8/T35+e8+XueSqCaPmEz9ofdbX6eSqE5iN/m4A8Qd9w/1bAEl2fPmafT3Axdv/ytlFeXUwTZyyf+NA3hWDGPrm+HXtHSdQ7nrz7fvv+MPFe/9Q3nAS+iYA3zcKCYAACIAACIAACIAACIAACIAACIAA1C2Komh++r9cogdv90M0+GoZAVHkSiGSaFmOmJdTRdESiKJ5Je4eovnSldoGNJ44gTBNbx+XH7tDYxwOniAPgEdygGWxTm/jBCAHV0u7xa90PV64IW0uOWdCapK7t600vfF2j4Ad5FCE4IopCSWMSg0Q4NgRVNKrwIBJ1ZDGxXO/5+fxhDvFQ87EsHxZMy9Sli/raMbjf9eqMpiciQG3yYOJwW1eQoBoesNBzG3yKdvqNwie1HMwiXFcwo7L7aMBtlSrC7c79RzyUm5w0f66Gk1vcJs8vFYHxUvy/u8leJz4N8t8vX5ccl04Chz5BOLR+mVVWXX5lsU4ncSOFevL7WFsJbYiPfQpcvJwhNsBxKiwcHDPNnoojzp8Jh8PnusiSMcLd1B8R5i+Igq5/BZKU3IEO8cIpoqw6L5NR8kjuOIaFR6GlmKdvmnhuFTsfqNwTBnzBOo+ZFua+jh3jAZtnksMu/b850wIfh1sVwVPhMEzKK9lz/+7Hi3Kx8CjOajVbVCEz3kIT1wyYnsD6s5t8tUaGLFpTfC7q2TH4rjzHMCoGgqTOJiMFi/TY5kduOJWHfzdtzdFrS4PYBwzhi0LAKcAdTcvKhur+VWQ3/TWcq/+LJG5VahUsILHUDGiGCmKy26cOrxlxwZUsMHlvVDW7lMQwghGOGZpmt6zcdFD47EhtQVyWySQRHUgVDzhmkeClyZFlGmiA5BH0WpyB+twPp/cgQpQBH0Lqt6qaTwfs+OW6Kl/RrdET/WqQi5BgWLDqNxmdV/Mo1X1QX5Ms0Pq/jmaP7d2/b6IVq3HW+a9qT7v6/TDNv2+tVA0hzz8klroc07AbXKmN98YQMppARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARCAD2//A2iD9ZsgY5XpAAAAAElFTkSuQmCC\") white"; rootElement.appendChild(splashElement); + // allow the screen to update + await asyncSleep(20); + /** @type {ArrayBuffer} */ var theEPWFileBuffer; if(assetsURI.startsWith("data:")) { @@ -319,6 +340,9 @@ window.main = async function() { const splashBinSlice = new Uint8Array(theEPWFileBuffer, splashDataOffset, splashDataLength); const splashMIMESlice = new Uint8Array(theEPWFileBuffer, splashMIMEOffset, splashMIMELength); const splashURL = URL.createObjectURL(new Blob([ splashBinSlice ], { "type": textDecoder.decode(splashMIMESlice) })); + + await preloadImage(splashURL, 50); + logInfo("Loaded splash img: " + splashURL); splashElement.style.background = "center / contain no-repeat url(\"" + splashURL + "\"), 0px 0px / 1000000% 1000000% no-repeat url(\"" + splashURL + "\") white"; diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformNetworking.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformNetworking.java index e036354b..d1387c3e 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformNetworking.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformNetworking.java @@ -1,21 +1,7 @@ package net.lax1dude.eaglercraft.v1_8.internal; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - import org.teavm.interop.Import; -import org.teavm.jso.JSObject; -import org.teavm.jso.JSProperty; import org.teavm.jso.core.JSString; -import org.teavm.jso.typedarrays.ArrayBuffer; -import org.teavm.jso.typedarrays.Uint8Array; - -import net.lax1dude.eaglercraft.v1_8.EagUtils; -import net.lax1dude.eaglercraft.v1_8.EaglerInputStream; -import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer; -import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator; -import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter; import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter; import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.WASMGCWebSocketClient; import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java index 0afae531..53a750be 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java @@ -3,8 +3,6 @@ package net.lax1dude.eaglercraft.v1_8.internal; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.HashMap; -import java.util.Map; import java.util.function.Consumer; import org.teavm.interop.Import; @@ -19,9 +17,13 @@ import org.teavm.jso.dom.html.HTMLElement; import org.teavm.jso.typedarrays.ArrayBuffer; import org.teavm.jso.typedarrays.Uint8Array; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; +import com.jcraft.jzlib.Deflater; import com.jcraft.jzlib.DeflaterOutputStream; import com.jcraft.jzlib.GZIPInputStream; import com.jcraft.jzlib.GZIPOutputStream; +import com.jcraft.jzlib.Inflater; import com.jcraft.jzlib.InflaterInputStream; import net.lax1dude.eaglercraft.v1_8.Filesystem; @@ -163,11 +165,21 @@ public class PlatformRuntime { } public static String getGLVersion() { - return PlatformOpenGL._wglGetString(RealOpenGLEnums.GL_VERSION); + String ret = PlatformOpenGL._wglGetString(RealOpenGLEnums.GL_VERSION); + if(ret != null) { + return ret; + }else { + return "null"; + } } public static String getGLRenderer() { - return PlatformOpenGL._wglGetString(RealOpenGLEnums.GL_RENDERER); + String ret = PlatformOpenGL._wglGetString(RealOpenGLEnums.GL_RENDERER); + if(ret != null) { + return ret; + }else { + return "null"; + } } public static ByteBuffer allocateByteBuffer(int length) { @@ -311,7 +323,7 @@ public class PlatformRuntime { @Import(module = "platformRuntime", name = "getNextEvent") private static native JSEagRuntimeEvent getNextEvent(); - private static final Map> waitingAsyncDownloads = new HashMap<>(); + private static final IntObjectMap> waitingAsyncDownloads = new IntObjectHashMap<>(); private static int asyncDownloadID = 0; private static void queueAsyncDownload(String uri, boolean forceCache, Consumer cb) { @@ -479,6 +491,23 @@ public class PlatformRuntime { return new DeflaterOutputStream(os); } + @SuppressWarnings("deprecation") + public static int deflateFull(byte[] input, int inputOff, int inputLen, byte[] output, int outputOff, + int outputLen) throws IOException { + Deflater df = new Deflater(); + df.setInput(input, inputOff, inputLen, false); + df.setOutput(output, outputOff, outputLen); + df.init(5); + int c; + do { + c = df.deflate(4); + if(c != 0 && c != 1) { + throw new IOException("Deflater failed! Code " + c); + } + }while(c != 1); + return (int)df.getTotalOut(); + } + public static OutputStream newGZIPOutputStream(OutputStream os) throws IOException { return new GZIPOutputStream(os); } @@ -487,6 +516,22 @@ public class PlatformRuntime { return new InflaterInputStream(is); } + @SuppressWarnings("deprecation") + public static int inflateFull(byte[] input, int inputOff, int inputLen, byte[] output, int outputOff, + int outputLen) throws IOException { + Inflater df = new Inflater(); + df.setInput(input, inputOff, inputLen, false); + df.setOutput(output, outputOff, outputLen); + int c; + do { + c = df.inflate(0); + if(c != 0 && c != 1) { + throw new IOException("Inflater failed! Code " + c); + } + }while(c != 1); + return (int)df.getTotalOut(); + } + public static InputStream newGZIPInputStream(InputStream is) throws IOException { return new GZIPInputStream(is); } diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformVoiceClient.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformVoiceClient.java index ec775acc..10454ef9 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformVoiceClient.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformVoiceClient.java @@ -20,6 +20,9 @@ import org.teavm.jso.webaudio.MediaStreamAudioDestinationNode; import org.teavm.jso.webaudio.MediaStreamAudioSourceNode; import org.teavm.jso.webaudio.PannerNode; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; + import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter; import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; @@ -133,7 +136,7 @@ public class PlatformVoiceClient { } static final Map peerList = new HashMap<>(); - static final Map peerListI = new HashMap<>(); + static final IntObjectMap peerListI = new IntObjectHashMap<>(); private static class VoicePeer { diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocByteBuffer.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocByteBuffer.java index 6726f237..6cc0d7d1 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocByteBuffer.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocByteBuffer.java @@ -4,7 +4,7 @@ import org.teavm.interop.Address; import org.teavm.interop.DirectMalloc; /** - * Copyright (c) 2024 lax1dude. All Rights Reserved. + * Copyright (c) 2024-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -18,7 +18,7 @@ import org.teavm.interop.DirectMalloc; * POSSIBILITY OF SUCH DAMAGE. * */ -public class DirectMallocByteBuffer implements ByteBuffer { +public class DirectMallocByteBuffer extends ByteBuffer { final Address address; final boolean original; diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocFloatBuffer.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocFloatBuffer.java index 6b1ebbd5..831bf045 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocFloatBuffer.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocFloatBuffer.java @@ -4,7 +4,7 @@ import org.teavm.interop.Address; import org.teavm.interop.DirectMalloc; /** - * Copyright (c) 2024 lax1dude. All Rights Reserved. + * Copyright (c) 2024-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -18,7 +18,7 @@ import org.teavm.interop.DirectMalloc; * POSSIBILITY OF SUCH DAMAGE. * */ -public class DirectMallocFloatBuffer implements FloatBuffer { +public class DirectMallocFloatBuffer extends FloatBuffer { final Address address; final boolean original; diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocIntBuffer.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocIntBuffer.java index 5cb69fd9..f333ddc5 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocIntBuffer.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocIntBuffer.java @@ -4,7 +4,7 @@ import org.teavm.interop.Address; import org.teavm.interop.DirectMalloc; /** - * Copyright (c) 2024 lax1dude. All Rights Reserved. + * Copyright (c) 2024-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -18,7 +18,7 @@ import org.teavm.interop.DirectMalloc; * POSSIBILITY OF SUCH DAMAGE. * */ -public class DirectMallocIntBuffer implements IntBuffer { +public class DirectMallocIntBuffer extends IntBuffer { final Address address; final boolean original; diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocShortBuffer.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocShortBuffer.java index 78863a1a..39e892cd 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocShortBuffer.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocShortBuffer.java @@ -4,7 +4,7 @@ import org.teavm.interop.Address; import org.teavm.interop.DirectMalloc; /** - * Copyright (c) 2024 lax1dude. All Rights Reserved. + * Copyright (c) 2024-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -18,7 +18,7 @@ import org.teavm.interop.DirectMalloc; * POSSIBILITY OF SUCH DAMAGE. * */ -public class DirectMallocShortBuffer implements ShortBuffer { +public class DirectMallocShortBuffer extends ShortBuffer { final Address address; final boolean original; diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/WASMGCBufferAllocator.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/WASMGCBufferAllocator.java index 7ebe8d6d..b3b97bd8 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/WASMGCBufferAllocator.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/WASMGCBufferAllocator.java @@ -202,7 +202,7 @@ public class WASMGCBufferAllocator { } public static Uint8Array getUnsignedByteBufferView(ShortBuffer buffer) { - DirectMallocIntBuffer buf = (DirectMallocIntBuffer)buffer; + DirectMallocShortBuffer buf = (DirectMallocShortBuffer)buffer; return getUnsignedByteBufferView0(buf.address.add(buf.position()), buf.remaining() << 1); } diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/BetterJSStringConverter.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/BetterJSStringConverter.java index 33a435a4..9027f51d 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/BetterJSStringConverter.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/BetterJSStringConverter.java @@ -1,13 +1,11 @@ package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm; import org.teavm.interop.Address; -import org.teavm.interop.DirectMalloc; import org.teavm.interop.Import; import org.teavm.interop.Unmanaged; import org.teavm.jso.core.JSArray; import org.teavm.jso.core.JSString; -import net.lax1dude.eaglercraft.v1_8.EagUtils; import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator; /** diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/TeaVMUtils.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/TeaVMUtils.java index befab836..bee3bbf3 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/TeaVMUtils.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/TeaVMUtils.java @@ -2,13 +2,6 @@ package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm; import org.teavm.jso.JSBody; import org.teavm.jso.JSObject; -import org.teavm.jso.typedarrays.ArrayBuffer; -import org.teavm.jso.typedarrays.ArrayBufferView; -import org.teavm.jso.typedarrays.Float32Array; -import org.teavm.jso.typedarrays.Int16Array; -import org.teavm.jso.typedarrays.Int32Array; -import org.teavm.jso.typedarrays.Int8Array; -import org.teavm.jso.typedarrays.Uint8Array; /** * Copyright (c) 2024 lax1dude. All Rights Reserved. diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/WASMGCWebSocketClient.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/WASMGCWebSocketClient.java index 001cb805..3f9716f1 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/WASMGCWebSocketClient.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/WASMGCWebSocketClient.java @@ -1,6 +1,5 @@ package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/ServerPlatformSingleplayer.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/ServerPlatformSingleplayer.java index 2cd9699a..628a464c 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/ServerPlatformSingleplayer.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/ServerPlatformSingleplayer.java @@ -23,7 +23,6 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter; import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2; import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter; import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.WASMGCClientConfigAdapter; -import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerIntegratedServerWorker; import net.lax1dude.eaglercraft.v1_8.sp.server.IWASMCrashCallback; import net.lax1dude.eaglercraft.v1_8.sp.server.internal.wasm_gc_teavm.JS_IPCPacketData; diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/wasm_gc_teavm/JS_IPCPacketData.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/wasm_gc_teavm/JS_IPCPacketData.java index 751f2aa8..a9fb29c4 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/wasm_gc_teavm/JS_IPCPacketData.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/wasm_gc_teavm/JS_IPCPacketData.java @@ -2,10 +2,12 @@ package net.lax1dude.eaglercraft.v1_8.sp.server.internal.wasm_gc_teavm; import org.teavm.jso.JSObject; import org.teavm.jso.JSProperty; +import org.teavm.jso.core.JSString; import org.teavm.jso.typedarrays.Uint8Array; import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData; import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter; +import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter; /** * Copyright (c) 2024 lax1dude. All Rights Reserved. @@ -25,13 +27,14 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter; public interface JS_IPCPacketData extends JSObject { @JSProperty - String getCh(); + JSString getCh(); @JSProperty Uint8Array getData(); default IPCPacketData internalize() { - return new IPCPacketData(getCh(), WASMGCDirectArrayConverter.externU8ArrayToByteArray(getData())); + return new IPCPacketData(BetterJSStringConverter.stringFromJS(getCh()), + WASMGCDirectArrayConverter.externU8ArrayToByteArray(getData())); } } diff --git a/wasm_gc_teavm/javascript/epw_meta.txt b/wasm_gc_teavm/javascript/epw_meta.txt index 9af6abcc..5a50c686 100755 --- a/wasm_gc_teavm/javascript/epw_meta.txt +++ b/wasm_gc_teavm/javascript/epw_meta.txt @@ -1,8 +1,8 @@ -client-version-integer=46 +client-version-integer=47 client-package-name=net.lax1dude.eaglercraft.v1_8.client client-origin-name=EaglercraftX -client-origin-version=u46 +client-origin-version=u47 client-origin-vendor=lax1dude client-fork-name=EaglercraftX -client-fork-version=u46 +client-fork-version=u47 client-fork-vendor=lax1dude diff --git a/wasm_gc_teavm/javascript_dist/bootstrap.js b/wasm_gc_teavm/javascript_dist/bootstrap.js index 1062d55e..1c94eac3 100755 --- a/wasm_gc_teavm/javascript_dist/bootstrap.js +++ b/wasm_gc_teavm/javascript_dist/bootstrap.js @@ -1,12 +1,13 @@ -(function(){'use strict';function g(a){console.log("LoaderBootstrap: [INFO] "+a)}function n(a){console.error("LoaderBootstrap: [ERROR] "+a)}var q=null; -function r(){const a=[];for(var c=0;64>c;++c)a["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charCodeAt(c)]=c;a[45]=62;a[95]=63;return function(b,d){var e=b.length-d;if(0>16&255,f[h++]=d>>8&255,f[h++]=d&255;2===e?(d=a[b.charCodeAt(k)]<<2|a[b.charCodeAt(k+1)]>>4,f[h++]=d&255):1===e&&(d=a[b.charCodeAt(k)]<<10|a[b.charCodeAt(k+1)]<<4|a[b.charCodeAt(k+2)]>>2,f[h++]=d>>8&255,f[h++]=d&255);return f.buffer}}function u(){return new Promise(function(a){setTimeout(a,20)})}function v(a){return new Promise(function(c){fetch(a,{cache:"force-cache"}).then(function(b){return b.arrayBuffer()}).then(c).catch(function(b){n("Failed to fetch URL! "+b);c(null)})})} -function w(a){return a.startsWith("data:application/octet-stream;base64,")?new Promise(function(c){v(a).then(function(b){if(b)c(b);else{console.log("LoaderBootstrap: [WARN] Failed to decode base64 via fetch, doing it the slow way instead...");try{q||=r();var d=q(a,37);c(d)}catch(e){n("Failed to decode base64! "+e),c(null)}}})}):v(a)} -function x(a,c){const b=document.createElement("h2");b.style.color="#AA0000";b.style.padding="25px";b.style.fontFamily="sans-serif";b.style.marginBlock="0px";b.appendChild(document.createTextNode(c));a.appendChild(b);c=document.createElement("h4");c.style.color="#AA0000";c.style.padding="25px";c.style.fontFamily="sans-serif";c.style.marginBlock="0px";c.appendChild(document.createTextNode("Try again later"));a.style.backgroundColor="white";a.appendChild(c)} -window.main=async function(){if("undefined"===typeof window.eaglercraftXOpts)n("window.eaglercraftXOpts is not defined!"),alert("window.eaglercraftXOpts is not defined!");else{var a=window.eaglercraftXOpts.container;if("string"!==typeof a)n("window.eaglercraftXOpts.container is not a string!"),alert("window.eaglercraftXOpts.container is not a string!");else{var c=window.eaglercraftXOpts.assetsURI;if("string"!==typeof c)if("object"===typeof c&&"object"===typeof c[0]&&"string"===typeof c[0].url)c=c[0].url; -else{n("window.eaglercraftXOpts.assetsURI is not a string!");alert("window.eaglercraftXOpts.assetsURI is not a string!");return}var b=document.getElementById(a);if(b){for(;a=b.lastChild;)b.removeChild(a);a=document.createElement("div");a.style.width="100%";a.style.height="100%";a.style.setProperty("image-rendering","pixelated");a.style.background='center / contain no-repeat url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAAAAAB3tzPbAAAACXBIWXMAAC4jAAAuIwF4pT92AAAG+UlEQVR42u2cy23jOhRATwbTwGwFvAJoF6BFGjColcGkASNuIPA6C68DN+BADZiCVxLSQBYqIGYBAbSdEvwWkvUzZWfymwlwCQwQUZeXPOT9URPkYs/3bj8QAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAH4x9vPvzFpAhAzM98UILmqfjDf1YT0N/cBk+71v+wDSczHmDeJ6TqO+SIfyD7IvC9g33Yc7dP6CQDxB+q62Hc2xnyJD2Sf5vuzL3Hi5MM0WbCN51u/Y/30ryEGmDVHlhwsY9Y7xlq0CuzVc4lh2n7NkGsnQ1nB7IefmrY/araJcbrq6Ryk9YqW4l3J/dHww1jdej+8kte042EW0Nba1hyWdl+9irq/FNXaD6BbQoexuvf+tQC2vX1+AFvP0kxiuyidfWwEbOtQtK0n0r6xbYCKsLcM21+pLZX3u4984Kq2xlnWDimllRudAXEpkGSHfqMzsmxfWnLWNf9aQznW4wMZWOMJxvGs/Ff5X+yPcD0g3dqZesdsI2f7Z2/73W2JSok9Gqu7P1q/I2qtj0qn/ZkTaCPWO2a0VyjrxY7sNUG1LxRlaE90MpDpGVeAxpaGobN2XPWH0aQVE1stfXPAj0+XzUmcob3aTRdVZ2+tRv+gMNBDaTkZ4k6uhtYPaK7iUkUcx9lgij92gZ6aXmxoDeK8D1hPfm18oBvTfPGwXoVG+4VfXcwl8dEOtCJS7De9M0VTqTA2p081O3kJ+uk5cU/RVN8C262Ms9HMlLHSmhNFTcc9u1uQRX4jMhqyNIk1GRk69a6hb0IDZ3pITnbfNqFuJWE9gbYrfmSqen/SiKy27G0VS20VWc+UEn59/YDPkc+0EunrAXQ/JXucYL+3VutyAqvP5wFvtEoyQPsMJMpKc3v7/Su9ALLkhAJDPCObGTDmonfNHAij3sg5866fmTHGnFt/crroh6vEv/Rq6vhEoP7hWWb2ylSQZP5zOVrDqVxSZnm/xL6OFnZwF3/4JoyGjyXu1X3n0rEFyE5Jzc5KEDfT7s2ZYs52s5e1HU88hB17nKTqAroXWPpXiHbN7R3Q8fVDbjzU6vb8hUbX67FWN8Xo4U5SIWjbukr1knY9XrcwS30aOuTatqa0vkA6cI05dyPrzWBbj7ZZrPUT2O7pdpKFtp4rph0E0AxtfN0u9kNVg25d4BPiDF0+R83dPol7/l4m4yQmQzdX+ISewqTnc8ngp94yaCan4vT+Hc228q8/T35+e8+XueSqCaPmEz9ofdbX6eSqE5iN/m4A8Qd9w/1bAEl2fPmafT3Axdv/ytlFeXUwTZyyf+NA3hWDGPrm+HXtHSdQ7nrz7fvv+MPFe/9Q3nAS+iYA3zcKCYAACIAACIAACIAACIAACIAACIAA1C2Komh++r9cogdv90M0+GoZAVHkSiGSaFmOmJdTRdESiKJ5Je4eovnSldoGNJ44gTBNbx+XH7tDYxwOniAPgEdygGWxTm/jBCAHV0u7xa90PV64IW0uOWdCapK7t600vfF2j4Ad5FCE4IopCSWMSg0Q4NgRVNKrwIBJ1ZDGxXO/5+fxhDvFQ87EsHxZMy9Sli/raMbjf9eqMpiciQG3yYOJwW1eQoBoesNBzG3yKdvqNwie1HMwiXFcwo7L7aMBtlSrC7c79RzyUm5w0f66Gk1vcJs8vFYHxUvy/u8leJz4N8t8vX5ccl04Chz5BOLR+mVVWXX5lsU4ncSOFevL7WFsJbYiPfQpcvJwhNsBxKiwcHDPNnoojzp8Jh8PnusiSMcLd1B8R5i+Igq5/BZKU3IEO8cIpoqw6L5NR8kjuOIaFR6GlmKdvmnhuFTsfqNwTBnzBOo+ZFua+jh3jAZtnksMu/b850wIfh1sVwVPhMEzKK9lz/+7Hi3Kx8CjOajVbVCEz3kIT1wyYnsD6s5t8tUaGLFpTfC7q2TH4rjzHMCoGgqTOJiMFi/TY5kduOJWHfzdtzdFrS4PYBwzhi0LAKcAdTcvKhur+VWQ3/TWcq/+LJG5VahUsILHUDGiGCmKy26cOrxlxwZUsMHlvVDW7lMQwghGOGZpmt6zcdFD47EhtQVyWySQRHUgVDzhmkeClyZFlGmiA5BH0WpyB+twPp/cgQpQBH0Lqt6qaTwfs+OW6Kl/RrdET/WqQi5BgWLDqNxmdV/Mo1X1QX5Ms0Pq/jmaP7d2/b6IVq3HW+a9qT7v6/TDNv2+tVA0hzz8klroc07AbXKmN98YQMppARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARCAD2//A2iD9ZsgY5XpAAAAAElFTkSuQmCC") white'; -b.appendChild(a);c.startsWith("data:")?(g('Downloading EPW file ""...'),c=await w(c)):(g('Downloading EPW file "'+c+'"...'),c=await v(c));var d=!1;c?384>c.byteLength&&(n("The EPW file is too short"),d=!0):d=!0;if(d)b.removeChild(a),x(b,"Failed to download EPW file!"),n("Failed to download EPW file!");else{var e=new DataView(c);if(608649541!==e.getUint32(0,!0)||1297301847!==e.getUint32(4,!0))n("The file is not an EPW file"),d=!0;var f=c.byteLength;e.getUint32(8,!0)!==f&&(n("The EPW file is the wrong length"), -d=!0);if(d)b.removeChild(a),x(b,"EPW file is invalid!"),n("EPW file is invalid!");else{var l=new TextDecoder("utf-8"),h=e.getUint32(100,!0),k=e.getUint32(104,!0),m=e.getUint32(108,!0),p=e.getUint32(112,!0);if(0>h||h+k>f||0>m||m+p>f)n("The EPW file contains an invalid offset (component: splash)"),d=!0;if(d)b.removeChild(a),x(b,"EPW file is invalid!"),n("EPW file is invalid!");else{h=new Uint8Array(c,h,k);m=new Uint8Array(c,m,p);l=URL.createObjectURL(new Blob([h],{type:l.decode(m)}));g("Loaded splash img: "+ -l);a.style.background='center / contain no-repeat url("'+l+'"), 0px 0px / 1000000% 1000000% no-repeat url("'+l+'") white';await u();p=e.getUint32(164,!0);h=e.getUint32(168,!0);m=e.getUint32(180,!0);e=e.getUint32(184,!0);if(0>p||p+h>f||0>m||m+e>f)n("The EPW file contains an invalid offset (component: loader)"),d=!0;if(d)b.removeChild(a),x(b,"EPW file is invalid!"),n("EPW file is invalid!");else{a=new Uint8Array(c,p,h);a=URL.createObjectURL(new Blob([a],{type:"text/javascript;charset=utf-8"}));g("Loaded loader.js: "+ -l);d=new Uint8Array(c,m,e);d=URL.createObjectURL(new Blob([d],{type:"application/wasm"}));g("Loaded loader.wasm: "+d);f={};for(const [t,y]of Object.entries(window.eaglercraftXOpts))"container"!==t&&"assetsURI"!==t&&(f[t]=y);window.__eaglercraftXLoaderContextPre={rootElement:b,eaglercraftXOpts:f,theEPWFileBuffer:c,loaderWASMURL:d,splashURL:l};g("Appending loader.js to document...");b=document.createElement("script");b.type="text/javascript";b.src=a;document.head.appendChild(b)}}}}}else b='window.eaglercraftXOpts.container "'+ -a+'" is not a known element id!',n(b),alert(b)}}};}).call(this); +(function(){'use strict';function g(a){console.log("LoaderBootstrap: [INFO] "+a)}function n(a){console.log("LoaderBootstrap: [WARN] "+a)}function q(a){console.error("LoaderBootstrap: [ERROR] "+a)}var r=null; +function u(){const a=[];for(var c=0;64>c;++c)a["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charCodeAt(c)]=c;a[45]=62;a[95]=63;return function(b,d){var e=b.length-d;if(0>16&255,f[h++]=d>>8&255,f[h++]=d&255;2===e?(d=a[b.charCodeAt(k)]<<2|a[b.charCodeAt(k+1)]>>4,f[h++]=d&255):1===e&&(d=a[b.charCodeAt(k)]<<10|a[b.charCodeAt(k+1)]<<4|a[b.charCodeAt(k+2)]>>2,f[h++]=d>>8&255,f[h++]=d&255);return f.buffer}}function v(){return new Promise(function(a){setTimeout(a,20)})} +function w(a){return new Promise(function(c){const b=new Image;b.addEventListener("load",c);b.addEventListener("error",function(){n("Failed to preload image: "+a);c()});b.src=a;setTimeout(c,50)})}function x(a){return new Promise(function(c){fetch(a,{cache:"force-cache"}).then(function(b){return b.arrayBuffer()}).then(c).catch(function(b){q("Failed to fetch URL! "+b);c(null)})})} +function y(a){return a.startsWith("data:application/octet-stream;base64,")?new Promise(function(c){x(a).then(function(b){if(b)c(b);else{n("Failed to decode base64 via fetch, doing it the slow way instead...");try{r||=u();var d=r(a,37);c(d)}catch(e){q("Failed to decode base64! "+e),c(null)}}})}):x(a)} +function z(a,c){const b=document.createElement("h2");b.style.color="#AA0000";b.style.padding="25px";b.style.fontFamily="sans-serif";b.style.marginBlock="0px";b.appendChild(document.createTextNode(c));a.appendChild(b);c=document.createElement("h4");c.style.color="#AA0000";c.style.padding="25px";c.style.fontFamily="sans-serif";c.style.marginBlock="0px";c.appendChild(document.createTextNode("Try again later"));a.style.backgroundColor="white";a.appendChild(c)} +window.main=async function(){if("undefined"===typeof window.eaglercraftXOpts)q("window.eaglercraftXOpts is not defined!"),alert("window.eaglercraftXOpts is not defined!");else{var a=window.eaglercraftXOpts.container;if("string"!==typeof a)q("window.eaglercraftXOpts.container is not a string!"),alert("window.eaglercraftXOpts.container is not a string!");else{var c=window.eaglercraftXOpts.assetsURI;if("string"!==typeof c)if("object"===typeof c&&"object"===typeof c[0]&&"string"===typeof c[0].url)c=c[0].url; +else{q("window.eaglercraftXOpts.assetsURI is not a string!");alert("window.eaglercraftXOpts.assetsURI is not a string!");return}var b=document.getElementById(a);if(b){for(;a=b.lastChild;)b.removeChild(a);a=document.createElement("div");a.style.width="100%";a.style.height="100%";a.style.setProperty("image-rendering","pixelated");a.style.background='center / contain no-repeat url("data:image/png;base64,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") white'; +b.appendChild(a);await v();c.startsWith("data:")?(g('Downloading EPW file ""...'),c=await y(c)):(g('Downloading EPW file "'+c+'"...'),c=await x(c));var d=!1;c?384>c.byteLength&&(q("The EPW file is too short"),d=!0):d=!0;if(d)b.removeChild(a),z(b,"Failed to download EPW file!"),q("Failed to download EPW file!");else{var e=new DataView(c);if(608649541!==e.getUint32(0,!0)||1297301847!==e.getUint32(4,!0))q("The file is not an EPW file"),d=!0;var f=c.byteLength;e.getUint32(8, +!0)!==f&&(q("The EPW file is the wrong length"),d=!0);if(d)b.removeChild(a),z(b,"EPW file is invalid!"),q("EPW file is invalid!");else{var l=new TextDecoder("utf-8"),h=e.getUint32(100,!0),k=e.getUint32(104,!0),m=e.getUint32(108,!0),p=e.getUint32(112,!0);if(0>h||h+k>f||0>m||m+p>f)q("The EPW file contains an invalid offset (component: splash)"),d=!0;if(d)b.removeChild(a),z(b,"EPW file is invalid!"),q("EPW file is invalid!");else{h=new Uint8Array(c,h,k);m=new Uint8Array(c,m,p);l=URL.createObjectURL(new Blob([h], +{type:l.decode(m)}));await w(l);g("Loaded splash img: "+l);a.style.background='center / contain no-repeat url("'+l+'"), 0px 0px / 1000000% 1000000% no-repeat url("'+l+'") white';await v();p=e.getUint32(164,!0);h=e.getUint32(168,!0);m=e.getUint32(180,!0);e=e.getUint32(184,!0);if(0>p||p+h>f||0>m||m+e>f)q("The EPW file contains an invalid offset (component: loader)"),d=!0;if(d)b.removeChild(a),z(b,"EPW file is invalid!"),q("EPW file is invalid!");else{a=new Uint8Array(c,p,h);a=URL.createObjectURL(new Blob([a], +{type:"text/javascript;charset=utf-8"}));g("Loaded loader.js: "+l);d=new Uint8Array(c,m,e);d=URL.createObjectURL(new Blob([d],{type:"application/wasm"}));g("Loaded loader.wasm: "+d);f={};for(const [t,A]of Object.entries(window.eaglercraftXOpts))"container"!==t&&"assetsURI"!==t&&(f[t]=A);window.__eaglercraftXLoaderContextPre={rootElement:b,eaglercraftXOpts:f,theEPWFileBuffer:c,loaderWASMURL:d,splashURL:l};g("Appending loader.js to document...");b=document.createElement("script");b.type="text/javascript"; +b.src=a;document.head.appendChild(b)}}}}}else b='window.eaglercraftXOpts.container "'+a+'" is not a known element id!',q(b),alert(b)}}};}).call(this);

The iteration is continued as long as the predicate returns true. + */ + public T forEach(T predicate); + + /** + * Returns a collection of keys of this container. The returned collection is a view over the key + * set and any modifications (if allowed) introduced to the collection will propagate to the + * associative container immediately. + */ + public CharCollection keys(); + + /** + * Returns a container view of all values present in this container. The returned collection is a + * view over the key set and any modifications (if allowed) introduced to the collection will + * propagate to the associative container immediately. + */ + public ByteContainer values(); +} diff --git a/src/main/java/com/carrotsearch/hppc/CharByteHashMap.java b/src/main/java/com/carrotsearch/hppc/CharByteHashMap.java new file mode 100755 index 00000000..93dd3c8f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharByteHashMap.java @@ -0,0 +1,1080 @@ +package com.carrotsearch.hppc; + +import static com.carrotsearch.hppc.Containers.*; +import static com.carrotsearch.hppc.HashContainers.*; + +import com.carrotsearch.hppc.cursors.*; +import com.carrotsearch.hppc.predicates.*; +import com.carrotsearch.hppc.procedures.*; +import java.util.*; + +/** + * A hash map of char to byte, implemented using open addressing with + * linear probing for collision resolution. + * + * @see HPPC interfaces diagram + */ +@com.carrotsearch.hppc.Generated( + date = "2024-06-04T15:20:16+0200", + value = "KTypeVTypeHashMap.java") +public class CharByteHashMap implements CharByteMap, Preallocable, Cloneable, Accountable { + + /** The array holding keys. */ + public char[] keys; + + /** The array holding values. */ + public byte[] values; + + /** + * The number of stored keys (assigned key slots), excluding the special "empty" key, if any (use + * {@link #size()} instead). + * + * @see #size() + */ + protected int assigned; + + /** Mask for slot scans in {@link #keys}. */ + protected int mask; + + /** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */ + protected int resizeAt; + + /** Special treatment for the "empty slot" key marker. */ + protected boolean hasEmptyKey; + + /** The load factor for {@link #keys}. */ + protected double loadFactor; + + /** Seed used to ensure the hash iteration order is different from an iteration to another. */ + protected int iterationSeed; + + /** New instance with sane defaults. */ + public CharByteHashMap() { + this(DEFAULT_EXPECTED_ELEMENTS); + } + + /** + * New instance with sane defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause buffer + * expansion (inclusive). + */ + public CharByteHashMap(int expectedElements) { + this(expectedElements, DEFAULT_LOAD_FACTOR); + } + + /** + * New instance with the provided defaults. + * + * @param expectedElements The expected number of elements guaranteed not to cause a rehash + * (inclusive). + * @param loadFactor The load factor for internal buffers. Insane load factors (zero, full + * capacity) are rejected by {@link #verifyLoadFactor(double)}. + */ + public CharByteHashMap(int expectedElements, double loadFactor) { + this.loadFactor = verifyLoadFactor(loadFactor); + iterationSeed = HashContainers.nextIterationSeed(); + ensureCapacity(expectedElements); + } + + /** Create a hash map from all key-value pairs of another container. */ + public CharByteHashMap(CharByteAssociativeContainer container) { + this(container.size()); + putAll(container); + } + + /** {@inheritDoc} */ + @Override + public byte put(char key, byte value) { + assert assigned < mask + 1; + + final int mask = this.mask; + if (((key) == 0)) { + byte previousValue = hasEmptyKey ? values[mask + 1] : ((byte) 0); + hasEmptyKey = true; + values[mask + 1] = value; + return previousValue; + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final byte previousValue = values[slot]; + values[slot] = value; + return previousValue; + } + slot = (slot + 1) & mask; + } + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(slot, key, value); + } else { + keys[slot] = key; + values[slot] = value; + } + + assigned++; + return ((byte) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int putAll(CharByteAssociativeContainer container) { + final int count = size(); + for (CharByteCursor c : container) { + put(c.key, c.value); + } + return size() - count; + } + + /** Puts all key/value pairs from a given iterable into this map. */ + @Override + public int putAll(Iterable iterable) { + final int count = size(); + for (CharByteCursor c : iterable) { + put(c.key, c.value); + } + return size() - count; + } + + /** + * If key exists, putValue is inserted into the map, otherwise any + * existing value is incremented by additionValue. + * + * @param key The key of the value to adjust. + * @param putValue The value to put if key does not exist. + * @param incrementValue The value to add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public byte putOrAdd(char key, byte putValue, byte incrementValue) { + assert assigned < mask + 1; + + int keyIndex = indexOf(key); + if (indexExists(keyIndex)) { + putValue = ((byte) ((values[keyIndex]) + (incrementValue))); + indexReplace(keyIndex, putValue); + } else { + indexInsert(keyIndex, key, putValue); + } + return putValue; + } + + /** + * Adds incrementValue to any existing value for the given key or + * inserts incrementValue if key did not previously exist. + * + * @param key The key of the value to adjust. + * @param incrementValue The value to put or add to the existing value if key exists. + * @return Returns the current value associated with key (after changes). + */ + @Override + public byte addTo(char key, byte incrementValue) { + return putOrAdd(key, incrementValue, incrementValue); + } + + /** {@inheritDoc} */ + @Override + public byte remove(char key) { + final int mask = this.mask; + if (((key) == 0)) { + if (!hasEmptyKey) { + return ((byte) 0); + } + hasEmptyKey = false; + byte previousValue = values[mask + 1]; + values[mask + 1] = ((byte) 0); + return previousValue; + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + final byte previousValue = values[slot]; + shiftConflictingKeys(slot); + return previousValue; + } + slot = (slot + 1) & mask; + } + + return ((byte) 0); + } + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharContainer other) { + final int before = size(); + + // Try to iterate over the smaller set of values or + // over the container that isn't implementing + // efficient contains() lookup. + + if (other.size() >= size() && other instanceof CharLookupContainer) { + if (hasEmptyKey && other.contains(((char) 0))) { + hasEmptyKey = false; + values[mask + 1] = ((byte) 0); + } + + final char[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + char existing; + if (!((existing = keys[slot]) == 0) && other.contains(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + } else { + for (CharCursor c : other) { + remove(c.value); + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharBytePredicate predicate) { + final int before = size(); + + final int mask = this.mask; + + if (hasEmptyKey) { + if (predicate.apply(((char) 0), values[mask + 1])) { + hasEmptyKey = false; + values[mask + 1] = ((byte) 0); + } + } + + final char[] keys = this.keys; + final byte[] values = this.values; + for (int slot = 0; slot <= mask; ) { + char existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing, values[slot])) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public int removeAll(CharPredicate predicate) { + final int before = size(); + + if (hasEmptyKey) { + if (predicate.apply(((char) 0))) { + hasEmptyKey = false; + values[mask + 1] = ((byte) 0); + } + } + + final char[] keys = this.keys; + for (int slot = 0, max = this.mask; slot <= max; ) { + char existing; + if (!((existing = keys[slot]) == 0) && predicate.apply(existing)) { + // Shift, do not increment slot. + shiftConflictingKeys(slot); + } else { + slot++; + } + } + + return before - size(); + } + + /** {@inheritDoc} */ + @Override + public byte get(char key) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : ((byte) 0); + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return ((byte) 0); + } + } + + /** {@inheritDoc} */ + @Override + public byte getOrDefault(char key, byte defaultValue) { + if (((key) == 0)) { + return hasEmptyKey ? values[mask + 1] : defaultValue; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return values[slot]; + } + slot = (slot + 1) & mask; + } + + return defaultValue; + } + } + + /** {@inheritDoc} */ + @Override + public boolean containsKey(char key) { + if (((key) == 0)) { + return hasEmptyKey; + } else { + final char[] keys = this.keys; + final int mask = this.mask; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return true; + } + slot = (slot + 1) & mask; + } + + return false; + } + } + + /** {@inheritDoc} */ + @Override + public int indexOf(char key) { + final int mask = this.mask; + if (((key) == 0)) { + return hasEmptyKey ? mask + 1 : ~(mask + 1); + } else { + final char[] keys = this.keys; + int slot = hashKey(key) & mask; + + char existing; + while (!((existing = keys[slot]) == 0)) { + if (((key) == (existing))) { + return slot; + } + slot = (slot + 1) & mask; + } + + return ~slot; + } + } + + /** {@inheritDoc} */ + @Override + public boolean indexExists(int index) { + assert index < 0 || (index >= 0 && index <= mask) || (index == mask + 1 && hasEmptyKey); + + return index >= 0; + } + + /** {@inheritDoc} */ + @Override + public byte indexGet(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + return values[index]; + } + + /** {@inheritDoc} */ + @Override + public byte indexReplace(int index, byte newValue) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + byte previousValue = values[index]; + values[index] = newValue; + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void indexInsert(int index, char key, byte value) { + assert index < 0 : "The index must not point at an existing key."; + + index = ~index; + if (((key) == 0)) { + assert index == mask + 1; + values[index] = value; + hasEmptyKey = true; + } else { + assert ((keys[index]) == 0); + + if (assigned == resizeAt) { + allocateThenInsertThenRehash(index, key, value); + } else { + keys[index] = key; + values[index] = value; + } + + assigned++; + } + } + + /** {@inheritDoc} */ + @Override + public byte indexRemove(int index) { + assert index >= 0 : "The index must point at an existing key."; + assert index <= mask || (index == mask + 1 && hasEmptyKey); + + byte previousValue = values[index]; + if (index > mask) { + assert index == mask + 1; + hasEmptyKey = false; + values[index] = ((byte) 0); + } else { + shiftConflictingKeys(index); + } + return previousValue; + } + + /** {@inheritDoc} */ + @Override + public void clear() { + assigned = 0; + hasEmptyKey = false; + + Arrays.fill(keys, ((char) 0)); + } + + /** {@inheritDoc} */ + @Override + public void release() { + assigned = 0; + hasEmptyKey = false; + + keys = null; + values = null; + ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS); + } + + /** {@inheritDoc} */ + @Override + public int size() { + return assigned + (hasEmptyKey ? 1 : 0); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = hasEmptyKey ? 0xDEADBEEF : 0; + for (CharByteCursor c : this) { + h += BitMixer.mix(c.key) + BitMixer.mix(c.value); + } + return h; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return (this == obj) + || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); + } + + /** Return true if all keys of some other container exist in this container. */ + protected boolean equalElements(CharByteHashMap other) { + if (other.size() != size()) { + return false; + } + + for (CharByteCursor c : other) { + char key = c.key; + if (!containsKey(key) || !((c.value) == (get(key)))) { + return false; + } + } + + return true; + } + + /** + * Ensure this container can hold at least the given number of keys (entries) without resizing its + * buffers. + * + * @param expectedElements The total number of keys, inclusive. + */ + @Override + public void ensureCapacity(int expectedElements) { + if (expectedElements > resizeAt || keys == null) { + final char[] prevKeys = this.keys; + final byte[] prevValues = this.values; + allocateBuffers(minBufferSize(expectedElements, loadFactor)); + if (prevKeys != null && !isEmpty()) { + rehash(prevKeys, prevValues); + } + } + } + + @Override + public long ramBytesAllocated() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowSizeOfArray(keys) + + RamUsageEstimator.shallowSizeOfArray(values); + } + + @Override + public long ramBytesUsed() { + // int: iterationSeed, assigned, mask, resizeAt + // double: loadFactor + // boolean: hasEmptyKey + return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + + 4 * Integer.BYTES + + Double.BYTES + + 1 + + RamUsageEstimator.shallowUsedSizeOfArray(keys, size()) + + RamUsageEstimator.shallowUsedSizeOfArray(values, size()); + } + + /** + * Provides the next iteration seed used to build the iteration starting slot and offset + * increment. This method does not need to be synchronized, what matters is that each thread gets + * a sequence of varying seeds. + */ + protected int nextIterationSeed() { + return iterationSeed = BitMixer.mixPhi(iterationSeed); + } + + /** An iterator implementation for {@link #iterator}. */ + private final class EntryIterator extends AbstractIterator { + private final CharByteCursor cursor; + private final int increment; + private int index; + private int slot; + + public EntryIterator() { + cursor = new CharByteCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharByteCursor fetch() { + final int mask = CharByteHashMap.this.mask; + while (index <= mask) { + char existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.key = existing; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.key = ((char) 0); + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return new EntryIterator(); + } + + /** {@inheritDoc} */ + @Override + public T forEach(T procedure) { + final char[] keys = this.keys; + final byte[] values = this.values; + + if (hasEmptyKey) { + procedure.apply(((char) 0), values[mask + 1]); + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + procedure.apply(keys[slot], values[slot]); + } + } + + return procedure; + } + + /** {@inheritDoc} */ + @Override + public T forEach(T predicate) { + final char[] keys = this.keys; + final byte[] values = this.values; + + if (hasEmptyKey) { + if (!predicate.apply(((char) 0), values[mask + 1])) { + return predicate; + } + } + + int seed = nextIterationSeed(); + int inc = iterationIncrement(seed); + for (int i = 0, mask = this.mask, slot = seed & mask; + i <= mask; + i++, slot = (slot + inc) & mask) { + if (!((keys[slot]) == 0)) { + if (!predicate.apply(keys[slot], values[slot])) { + break; + } + } + } + + return predicate; + } + + /** + * Returns a specialized view of the keys of this associated container. The view additionally + * implements {@link ObjectLookupContainer}. + */ + public KeysContainer keys() { + return new KeysContainer(); + } + + /** A view of the keys inside this hash map. */ + public final class KeysContainer extends AbstractCharCollection implements CharLookupContainer { + private final CharByteHashMap owner = CharByteHashMap.this; + + @Override + public boolean contains(char e) { + return owner.containsKey(e); + } + + @Override + public T forEach(final T procedure) { + owner.forEach((CharByteProcedure) (k, v) -> procedure.apply(k)); + return procedure; + } + + @Override + public T forEach(final T predicate) { + owner.forEach((CharBytePredicate) (key, value) -> predicate.apply(key)); + return predicate; + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public Iterator iterator() { + return new KeysIterator(); + } + + @Override + public int size() { + return owner.size(); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + + @Override + public int removeAll(CharPredicate predicate) { + return owner.removeAll(predicate); + } + + @Override + public int removeAll(final char e) { + if (owner.containsKey(e)) { + owner.remove(e); + return 1; + } else { + return 0; + } + } + } + ; + + /** An iterator over the set of assigned keys. */ + private final class KeysIterator extends AbstractIterator { + private final CharCursor cursor; + private final int increment; + private int index; + private int slot; + + public KeysIterator() { + cursor = new CharCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected CharCursor fetch() { + final int mask = CharByteHashMap.this.mask; + while (index <= mask) { + char existing; + index++; + slot = (slot + increment) & mask; + if (!((existing = keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = existing; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index++; + cursor.value = ((char) 0); + return cursor; + } + + return done(); + } + } + + /** + * @return Returns a container with all values stored in this map. + */ + @Override + public ByteCollection values() { + return new ValuesContainer(); + } + + /** A view over the set of values of this map. */ + private final class ValuesContainer extends AbstractByteCollection { + private final CharByteHashMap owner = CharByteHashMap.this; + + @Override + public int size() { + return owner.size(); + } + + @Override + public boolean isEmpty() { + return owner.isEmpty(); + } + + @Override + public boolean contains(byte value) { + for (CharByteCursor c : owner) { + if (((value) == (c.value))) { + return true; + } + } + return false; + } + + @Override + public T forEach(T procedure) { + for (CharByteCursor c : owner) { + procedure.apply(c.value); + } + return procedure; + } + + @Override + public T forEach(T predicate) { + for (CharByteCursor c : owner) { + if (!predicate.apply(c.value)) { + break; + } + } + return predicate; + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public int removeAll(final byte e) { + return owner.removeAll((key, value) -> ((e) == (value))); + } + + @Override + public int removeAll(final BytePredicate predicate) { + return owner.removeAll((key, value) -> predicate.apply(value)); + } + + @Override + public void clear() { + owner.clear(); + } + + @Override + public void release() { + owner.release(); + } + } + + /** An iterator over the set of assigned values. */ + private final class ValuesIterator extends AbstractIterator { + private final ByteCursor cursor; + private final int increment; + private int index; + private int slot; + + public ValuesIterator() { + cursor = new ByteCursor(); + int seed = nextIterationSeed(); + increment = iterationIncrement(seed); + slot = seed & mask; + } + + @Override + protected ByteCursor fetch() { + final int mask = CharByteHashMap.this.mask; + while (index <= mask) { + index++; + slot = (slot + increment) & mask; + if (!((keys[slot]) == 0)) { + cursor.index = slot; + cursor.value = values[slot]; + return cursor; + } + } + + if (index == mask + 1 && hasEmptyKey) { + cursor.index = index; + cursor.value = values[index++]; + return cursor; + } + + return done(); + } + } + + /** {@inheritDoc} */ + @Override + public CharByteHashMap clone() { + try { + + CharByteHashMap cloned = (CharByteHashMap) super.clone(); + cloned.keys = keys.clone(); + cloned.values = values.clone(); + cloned.hasEmptyKey = hasEmptyKey; + cloned.iterationSeed = HashContainers.nextIterationSeed(); + return cloned; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Convert the contents of this map to a human-friendly string. */ + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("["); + + boolean first = true; + for (CharByteCursor cursor : this) { + if (!first) { + buffer.append(", "); + } + buffer.append(cursor.key); + buffer.append("=>"); + buffer.append(cursor.value); + first = false; + } + buffer.append("]"); + return buffer.toString(); + } + + @Override + public String visualizeKeyDistribution(int characters) { + return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters); + } + + /** Creates a hash map from two index-aligned arrays of key-value pairs. */ + public static CharByteHashMap from(char[] keys, byte[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException( + "Arrays of keys and values must have an identical length."); + } + + CharByteHashMap map = new CharByteHashMap(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + + return map; + } + + /** + * Returns a hash code for the given key. + * + *