remove Windows support, revert new guava to small version
This commit is contained in:
parent
fd84384f10
commit
920405d8c5
264 changed files with 22715 additions and 377 deletions
|
@ -43,11 +43,11 @@ import javax.imageio.ImageIO;
|
|||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListenableFutureTask;
|
||||
import game.collect.Lists;
|
||||
import game.collect.Maps;
|
||||
import game.future.Futures;
|
||||
import game.future.ListenableFuture;
|
||||
import game.future.ListenableFutureTask;
|
||||
|
||||
import game.audio.AudioInterface;
|
||||
import game.audio.SoundManager;
|
||||
|
|
|
@ -16,12 +16,12 @@ import java.util.concurrent.ExecutionException;
|
|||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListenableFutureTask;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import game.collect.Lists;
|
||||
import game.collect.Maps;
|
||||
import game.future.Futures;
|
||||
import game.future.ListenableFuture;
|
||||
import game.future.ListenableFutureTask;
|
||||
import game.future.ThreadFactoryBuilder;
|
||||
|
||||
import game.color.TextColor;
|
||||
import game.command.ScriptEnvironment;
|
||||
|
|
|
@ -2,8 +2,8 @@ package game.ai;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import java.util.function.Predicate;
|
||||
import game.util.Predicates;
|
||||
|
||||
import game.entity.Entity;
|
||||
import game.entity.types.EntityLiving;
|
||||
|
@ -39,7 +39,7 @@ public class EntityAIAvoidEntity<T extends Entity> extends EntityAIBase
|
|||
{
|
||||
this.canBeSeenSelector = new Predicate<Entity>()
|
||||
{
|
||||
public boolean apply(Entity p_apply_1_)
|
||||
public boolean test(Entity p_apply_1_)
|
||||
{
|
||||
return p_apply_1_.isEntityAlive() && EntityAIAvoidEntity.this.theEntity.getEntitySenses().canSee(p_apply_1_);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package game.ai;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import java.util.function.Predicate;
|
||||
import game.util.Predicates;
|
||||
|
||||
import game.block.BlockTallGrass;
|
||||
import game.entity.animal.EntitySheep;
|
||||
|
@ -40,7 +40,7 @@ public class EntityAIEatGrass extends EntityAIBase
|
|||
else
|
||||
{
|
||||
BlockPos blockpos = new BlockPos(this.grassEaterEntity.posX, this.grassEaterEntity.posY, this.grassEaterEntity.posZ);
|
||||
return field_179505_b.apply(this.entityWorld.getState(blockpos)) ? true : this.entityWorld.getState(blockpos.down()).getBlock() == Blocks.grass;
|
||||
return field_179505_b.test(this.entityWorld.getState(blockpos)) ? true : this.entityWorld.getState(blockpos.down()).getBlock() == Blocks.grass;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,7 @@ public class EntityAIEatGrass extends EntityAIBase
|
|||
{
|
||||
BlockPos blockpos = new BlockPos(this.grassEaterEntity.posX, this.grassEaterEntity.posY, this.grassEaterEntity.posZ);
|
||||
|
||||
if (field_179505_b.apply(this.entityWorld.getState(blockpos)))
|
||||
if (field_179505_b.test(this.entityWorld.getState(blockpos)))
|
||||
{
|
||||
if (Config.mobGrief)
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@ package game.ai;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import game.entity.attributes.AttributeInstance;
|
||||
import game.entity.attributes.Attributes;
|
||||
|
@ -29,7 +29,7 @@ public class EntityAIFindEntityNearest extends EntityAIBase
|
|||
|
||||
this.field_179443_c = new Predicate<EntityLiving>()
|
||||
{
|
||||
public boolean apply(EntityLiving p_apply_1_)
|
||||
public boolean test(EntityLiving p_apply_1_)
|
||||
{
|
||||
double d0 = EntityAIFindEntityNearest.this.getFollowRange();
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.ai;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import game.collect.Lists;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.pathfinding.PathEntity;
|
||||
|
|
|
@ -4,7 +4,7 @@ import java.util.Collections;
|
|||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import game.entity.Entity;
|
||||
import game.entity.types.EntityLiving;
|
||||
|
@ -38,9 +38,9 @@ public class EntityAINearestAttackableTarget<T extends EntityLiving> extends Ent
|
|||
this.setMutexBits(1);
|
||||
this.targetEntitySelector = new Predicate<T>()
|
||||
{
|
||||
public boolean apply(T p_apply_1_)
|
||||
public boolean test(T p_apply_1_)
|
||||
{
|
||||
if (targetSelector != null && !targetSelector.apply(p_apply_1_))
|
||||
if (targetSelector != null && !targetSelector.test(p_apply_1_))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.ai;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import game.collect.Maps;
|
||||
|
||||
import game.block.Block;
|
||||
import game.entity.npc.EntityNPC;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package game.ai;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.entity.types.EntityTameable;
|
||||
|
|
|
@ -3,7 +3,7 @@ package game.ai;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import game.collect.Lists;
|
||||
|
||||
public class EntityAITasks
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.ai;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import game.collect.Lists;
|
||||
|
||||
import game.entity.Entity;
|
||||
import game.entity.types.EntityLiving;
|
||||
|
|
|
@ -10,7 +10,7 @@ import javax.sound.sampled.DataLine.Info;
|
|||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.SourceDataLine;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import game.collect.Lists;
|
||||
|
||||
import game.log.Log;
|
||||
|
||||
|
|
|
@ -6,10 +6,10 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import game.collect.BiMap;
|
||||
import game.collect.HashBiMap;
|
||||
import game.collect.Lists;
|
||||
import game.collect.Maps;
|
||||
|
||||
import game.Game;
|
||||
import game.entity.npc.EntityNPC;
|
||||
|
|
|
@ -3,8 +3,8 @@ package game.biome;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import game.collect.Lists;
|
||||
import game.collect.Maps;
|
||||
|
||||
import game.block.Block;
|
||||
import game.block.BlockColored;
|
||||
|
|
|
@ -10,13 +10,13 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.UnmodifiableIterator;
|
||||
import java.util.function.Function;
|
||||
import game.collect.ImmutableList;
|
||||
import game.collect.ImmutableMap;
|
||||
import game.collect.Iterables;
|
||||
import game.collect.Lists;
|
||||
import game.collect.Maps;
|
||||
import game.collect.UnmodifiableIterator;
|
||||
|
||||
import game.audio.SoundType;
|
||||
import game.enchantment.EnchantmentHelper;
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.block;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import game.collect.Lists;
|
||||
|
||||
import game.entity.Entity;
|
||||
import game.entity.npc.EntityNPC;
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.block;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import game.collect.Lists;
|
||||
|
||||
import game.entity.npc.EntityNPC;
|
||||
import game.init.Blocks;
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.block;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import game.collect.Lists;
|
||||
|
||||
import game.entity.Entity;
|
||||
import game.entity.npc.EntityNPC;
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.block;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import game.collect.Maps;
|
||||
|
||||
import game.init.Blocks;
|
||||
import game.init.Config;
|
||||
|
|
|
@ -4,7 +4,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import game.collect.Sets;
|
||||
|
||||
import game.entity.Entity;
|
||||
import game.item.Item;
|
||||
|
|
|
@ -3,9 +3,9 @@ package game.block;
|
|||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.function.Predicate;
|
||||
import game.collect.Filter;
|
||||
import game.collect.Lists;
|
||||
|
||||
import game.init.Blocks;
|
||||
import game.init.Config;
|
||||
|
@ -81,7 +81,7 @@ public abstract class BlockFlower extends BlockBush
|
|||
{
|
||||
this.type = PropertyEnum.<BlockFlower.EnumFlowerType>create("type", BlockFlower.EnumFlowerType.class, new Predicate<BlockFlower.EnumFlowerType>()
|
||||
{
|
||||
public boolean apply(BlockFlower.EnumFlowerType p_apply_1_)
|
||||
public boolean test(BlockFlower.EnumFlowerType p_apply_1_)
|
||||
{
|
||||
return p_apply_1_.getBlockType() == BlockFlower.this.getBlockType();
|
||||
}
|
||||
|
@ -202,9 +202,9 @@ public abstract class BlockFlower extends BlockBush
|
|||
static {
|
||||
for (final BlockFlower.EnumFlowerColor blockflower$enumflowercolor : BlockFlower.EnumFlowerColor.values())
|
||||
{
|
||||
Collection<BlockFlower.EnumFlowerType> collection = Collections2.<BlockFlower.EnumFlowerType>filter(Lists.newArrayList(values()), new Predicate<BlockFlower.EnumFlowerType>()
|
||||
Collection<BlockFlower.EnumFlowerType> collection = Filter.<BlockFlower.EnumFlowerType>filter(Lists.newArrayList(values()), new Predicate<BlockFlower.EnumFlowerType>()
|
||||
{
|
||||
public boolean apply(BlockFlower.EnumFlowerType p_apply_1_)
|
||||
public boolean test(BlockFlower.EnumFlowerType p_apply_1_)
|
||||
{
|
||||
return p_apply_1_.getBlockType() == blockflower$enumflowercolor;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.block;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import game.entity.Entity;
|
||||
import game.entity.npc.EntityNPC;
|
||||
|
@ -84,7 +84,7 @@ public class BlockHopper extends BlockContainer
|
|||
|
||||
public static final PropertyDirection FACING = PropertyDirection.create("facing", new Predicate<Facing>()
|
||||
{
|
||||
public boolean apply(Facing p_apply_1_)
|
||||
public boolean test(Facing p_apply_1_)
|
||||
{
|
||||
return p_apply_1_ != Facing.UP;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.block;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import game.collect.Lists;
|
||||
|
||||
import game.audio.SoundType;
|
||||
import game.color.Colorizer;
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.block;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import game.collect.Lists;
|
||||
|
||||
import game.audio.SoundType;
|
||||
import game.entity.Entity;
|
||||
|
|
|
@ -19,7 +19,7 @@ public class BlockPumpkin extends BlockDirectional
|
|||
// private BlockPattern golemPattern;
|
||||
// private static final Predicate<IBlockState> field_181085_Q = new Predicate<IBlockState>()
|
||||
// {
|
||||
// public boolean apply(IBlockState p_apply_1_)
|
||||
// public boolean test(IBlockState p_apply_1_)
|
||||
// {
|
||||
// return p_apply_1_ != null && (p_apply_1_.getBlock() == Blocks.pumpkin || p_apply_1_.getBlock() == Blocks.lit_pumpkin);
|
||||
// }
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.block;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import game.collect.Lists;
|
||||
|
||||
import game.init.Blocks;
|
||||
import game.item.CheatTab;
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.block;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import game.entity.Entity;
|
||||
import game.entity.item.EntityCart;
|
||||
|
@ -25,7 +25,7 @@ public class BlockRailDetector extends BlockRailBase
|
|||
{
|
||||
public static final PropertyEnum<BlockRailBase.EnumRailDirection> SHAPE = PropertyEnum.<BlockRailBase.EnumRailDirection>create("shape", BlockRailBase.EnumRailDirection.class, new Predicate<BlockRailBase.EnumRailDirection>()
|
||||
{
|
||||
public boolean apply(BlockRailBase.EnumRailDirection p_apply_1_)
|
||||
public boolean test(BlockRailBase.EnumRailDirection p_apply_1_)
|
||||
{
|
||||
return p_apply_1_ != BlockRailBase.EnumRailDirection.NORTH_EAST && p_apply_1_ != BlockRailBase.EnumRailDirection.NORTH_WEST && p_apply_1_ != BlockRailBase.EnumRailDirection.SOUTH_EAST && p_apply_1_ != BlockRailBase.EnumRailDirection.SOUTH_WEST;
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ public class BlockRailDetector extends BlockRailBase
|
|||
// }
|
||||
|
||||
List<EntityCart> list1 = this.<EntityCart>findMinecarts(worldIn, pos, EntityCart.class, new Predicate<EntityCart>() {
|
||||
public boolean apply(EntityCart entity) {
|
||||
public boolean test(EntityCart entity) {
|
||||
return entity instanceof IInventory && entity.isEntityAlive();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package game.block;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import game.properties.IProperty;
|
||||
import game.properties.PropertyBool;
|
||||
|
@ -14,7 +14,7 @@ public class BlockRailPowered extends BlockRailBase
|
|||
{
|
||||
public static final PropertyEnum<BlockRailBase.EnumRailDirection> SHAPE = PropertyEnum.<BlockRailBase.EnumRailDirection>create("shape", BlockRailBase.EnumRailDirection.class, new Predicate<BlockRailBase.EnumRailDirection>()
|
||||
{
|
||||
public boolean apply(BlockRailBase.EnumRailDirection p_apply_1_)
|
||||
public boolean test(BlockRailBase.EnumRailDirection p_apply_1_)
|
||||
{
|
||||
return p_apply_1_ != BlockRailBase.EnumRailDirection.NORTH_EAST && p_apply_1_ != BlockRailBase.EnumRailDirection.NORTH_WEST && p_apply_1_ != BlockRailBase.EnumRailDirection.SOUTH_EAST && p_apply_1_ != BlockRailBase.EnumRailDirection.SOUTH_WEST;
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ public class BlockRedstoneComparator extends BlockRedstoneDiode implements ITile
|
|||
// {
|
||||
// List<EntityFrame> list = worldIn.<EntityFrame>getEntitiesWithinAABB(EntityFrame.class, new BoundingBox((double)pos.getX(), (double)pos.getY(), (double)pos.getZ(), (double)(pos.getX() + 1), (double)(pos.getY() + 1), (double)(pos.getZ() + 1)), new Predicate<Entity>()
|
||||
// {
|
||||
// public boolean apply(Entity p_apply_1_)
|
||||
// public boolean test(Entity p_apply_1_)
|
||||
// {
|
||||
// return p_apply_1_ != null && p_apply_1_.getHorizontalFacing() == facing;
|
||||
// }
|
||||
|
|
|
@ -3,8 +3,8 @@ package game.block;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import game.collect.Lists;
|
||||
import game.collect.Maps;
|
||||
|
||||
import game.init.Blocks;
|
||||
import game.init.ItemRegistry;
|
||||
|
|
|
@ -4,8 +4,8 @@ import java.util.EnumSet;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import game.collect.Lists;
|
||||
import game.collect.Sets;
|
||||
|
||||
import game.init.Blocks;
|
||||
import game.init.Items;
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.block;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import game.collect.Lists;
|
||||
|
||||
import game.init.Blocks;
|
||||
import game.init.Config;
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.block;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import game.collect.Lists;
|
||||
|
||||
import game.entity.Entity;
|
||||
import game.entity.types.EntityLiving;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package game.block;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import game.init.Blocks;
|
||||
import game.init.Config;
|
||||
|
@ -27,7 +27,7 @@ public class BlockStem extends BlockBush implements IGrowable
|
|||
public static final PropertyInteger AGE = PropertyInteger.create("age", 0, 7);
|
||||
public static final PropertyDirection FACING = PropertyDirection.create("facing", new Predicate<Facing>()
|
||||
{
|
||||
public boolean apply(Facing p_apply_1_)
|
||||
public boolean test(Facing p_apply_1_)
|
||||
{
|
||||
return p_apply_1_ != Facing.DOWN;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package game.block;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.init.Blocks;
|
||||
|
@ -28,7 +28,7 @@ public class BlockTorch extends Block
|
|||
{
|
||||
public static final PropertyDirection FACING = PropertyDirection.create("facing", new Predicate<Facing>()
|
||||
{
|
||||
public boolean apply(Facing p_apply_1_)
|
||||
public boolean test(Facing p_apply_1_)
|
||||
{
|
||||
return p_apply_1_ != Facing.DOWN;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import game.collect.Lists;
|
||||
|
||||
import game.block.Block;
|
||||
import game.block.BlockDoor;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package game.clipboard;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class Rotation {
|
||||
private final RotationValue[] values;
|
||||
|
@ -9,7 +9,7 @@ public class Rotation {
|
|||
public Rotation(RotationValue[] values, Predicate<Integer> predicate) {
|
||||
this.values = values;
|
||||
for(int z = 0; z < 16; z++) {
|
||||
if(predicate != null && !predicate.apply(z)) {
|
||||
if(predicate != null && !predicate.test(z)) {
|
||||
this.dirFlags[z] = false;
|
||||
continue;
|
||||
}
|
||||
|
|
399
java/src/game/collect/AbstractBiMap.java
Normal file
399
java/src/game/collect/AbstractBiMap.java
Normal file
|
@ -0,0 +1,399 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.CollectPreconditions.checkRemove;
|
||||
import static game.collect.Preconditions.checkArgument;
|
||||
import static game.collect.Preconditions.checkState;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A general-purpose bimap implementation using any two backing {@code Map}
|
||||
* instances.
|
||||
*
|
||||
* <p>Note that this class contains {@code equals()} calls that keep it from
|
||||
* supporting {@code IdentityHashMap} backing maps.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @author Mike Bostock
|
||||
*/
|
||||
|
||||
abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
|
||||
implements BiMap<K, V>, Serializable {
|
||||
|
||||
private transient Map<K, V> delegate;
|
||||
transient AbstractBiMap<V, K> inverse;
|
||||
|
||||
/** Package-private constructor for creating a map-backed bimap. */
|
||||
AbstractBiMap(Map<K, V> forward, Map<V, K> backward) {
|
||||
setDelegates(forward, backward);
|
||||
}
|
||||
|
||||
/** Private constructor for inverse bimap. */
|
||||
private AbstractBiMap(Map<K, V> backward, AbstractBiMap<V, K> forward) {
|
||||
delegate = backward;
|
||||
inverse = forward;
|
||||
}
|
||||
|
||||
@Override protected Map<K, V> delegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns its input, or throws an exception if this is not a valid key.
|
||||
*/
|
||||
K checkKey(K key) {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns its input, or throws an exception if this is not a valid value.
|
||||
*/
|
||||
V checkValue(V value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the delegate maps going in each direction. Called by the
|
||||
* constructor and by subclasses during deserialization.
|
||||
*/
|
||||
void setDelegates(Map<K, V> forward, Map<V, K> backward) {
|
||||
checkState(delegate == null);
|
||||
checkState(inverse == null);
|
||||
checkArgument(forward.isEmpty());
|
||||
checkArgument(backward.isEmpty());
|
||||
checkArgument(forward != backward);
|
||||
delegate = forward;
|
||||
inverse = new Inverse<V, K>(backward, this);
|
||||
}
|
||||
|
||||
void setInverse(AbstractBiMap<V, K> inverse) {
|
||||
this.inverse = inverse;
|
||||
}
|
||||
|
||||
// Query Operations (optimizations)
|
||||
|
||||
@Override public boolean containsValue(Object value) {
|
||||
return inverse.containsKey(value);
|
||||
}
|
||||
|
||||
// Modification Operations
|
||||
|
||||
@Override public V put(K key, V value) {
|
||||
return putInBothMaps(key, value, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V forcePut(K key, V value) {
|
||||
return putInBothMaps(key, value, true);
|
||||
}
|
||||
|
||||
private V putInBothMaps(K key, V value, boolean force) {
|
||||
checkKey(key);
|
||||
checkValue(value);
|
||||
boolean containedKey = containsKey(key);
|
||||
if (containedKey && Preconditions.equal(value, get(key))) {
|
||||
return value;
|
||||
}
|
||||
if (force) {
|
||||
inverse().remove(value);
|
||||
} else {
|
||||
checkArgument(!containsValue(value), "value already present: %s", value);
|
||||
}
|
||||
V oldValue = delegate.put(key, value);
|
||||
updateInverseMap(key, containedKey, oldValue, value);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
private void updateInverseMap(
|
||||
K key, boolean containedKey, V oldValue, V newValue) {
|
||||
if (containedKey) {
|
||||
removeFromInverseMap(oldValue);
|
||||
}
|
||||
inverse.delegate.put(newValue, key);
|
||||
}
|
||||
|
||||
@Override public V remove(Object key) {
|
||||
return containsKey(key) ? removeFromBothMaps(key) : null;
|
||||
}
|
||||
|
||||
private V removeFromBothMaps(Object key) {
|
||||
V oldValue = delegate.remove(key);
|
||||
removeFromInverseMap(oldValue);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
private void removeFromInverseMap(V oldValue) {
|
||||
inverse.delegate.remove(oldValue);
|
||||
}
|
||||
|
||||
// Bulk Operations
|
||||
|
||||
@Override public void putAll(Map<? extends K, ? extends V> map) {
|
||||
for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
|
||||
put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void clear() {
|
||||
delegate.clear();
|
||||
inverse.delegate.clear();
|
||||
}
|
||||
|
||||
// Views
|
||||
|
||||
@Override
|
||||
public BiMap<V, K> inverse() {
|
||||
return inverse;
|
||||
}
|
||||
|
||||
private transient Set<K> keySet;
|
||||
|
||||
@Override public Set<K> keySet() {
|
||||
Set<K> result = keySet;
|
||||
return (result == null) ? keySet = new KeySet() : result;
|
||||
}
|
||||
|
||||
private class KeySet extends ForwardingSet<K> {
|
||||
@Override protected Set<K> delegate() {
|
||||
return delegate.keySet();
|
||||
}
|
||||
|
||||
@Override public void clear() {
|
||||
AbstractBiMap.this.clear();
|
||||
}
|
||||
|
||||
@Override public boolean remove(Object key) {
|
||||
if (!contains(key)) {
|
||||
return false;
|
||||
}
|
||||
removeFromBothMaps(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean removeAll(Collection<?> keysToRemove) {
|
||||
return standardRemoveAll(keysToRemove);
|
||||
}
|
||||
|
||||
@Override public boolean retainAll(Collection<?> keysToRetain) {
|
||||
return standardRetainAll(keysToRetain);
|
||||
}
|
||||
|
||||
@Override public Iterator<K> iterator() {
|
||||
return Maps.keyIterator(entrySet().iterator());
|
||||
}
|
||||
}
|
||||
|
||||
private transient Set<V> valueSet;
|
||||
|
||||
@Override public Set<V> values() {
|
||||
/*
|
||||
* We can almost reuse the inverse's keySet, except we have to fix the
|
||||
* iteration order so that it is consistent with the forward map.
|
||||
*/
|
||||
Set<V> result = valueSet;
|
||||
return (result == null) ? valueSet = new ValueSet() : result;
|
||||
}
|
||||
|
||||
private class ValueSet extends ForwardingSet<V> {
|
||||
final Set<V> valuesDelegate = inverse.keySet();
|
||||
|
||||
@Override protected Set<V> delegate() {
|
||||
return valuesDelegate;
|
||||
}
|
||||
|
||||
@Override public Iterator<V> iterator() {
|
||||
return Maps.valueIterator(entrySet().iterator());
|
||||
}
|
||||
|
||||
@Override public Object[] toArray() {
|
||||
return standardToArray();
|
||||
}
|
||||
|
||||
@Override public <T> T[] toArray(T[] array) {
|
||||
return standardToArray(array);
|
||||
}
|
||||
|
||||
// @Override public String toString() {
|
||||
// return standardToString();
|
||||
// }
|
||||
}
|
||||
|
||||
private transient Set<Entry<K, V>> entrySet;
|
||||
|
||||
@Override public Set<Entry<K, V>> entrySet() {
|
||||
Set<Entry<K, V>> result = entrySet;
|
||||
return (result == null) ? entrySet = new EntrySet() : result;
|
||||
}
|
||||
|
||||
private class EntrySet extends ForwardingSet<Entry<K, V>> {
|
||||
final Set<Entry<K, V>> esDelegate = delegate.entrySet();
|
||||
|
||||
@Override protected Set<Entry<K, V>> delegate() {
|
||||
return esDelegate;
|
||||
}
|
||||
|
||||
@Override public void clear() {
|
||||
AbstractBiMap.this.clear();
|
||||
}
|
||||
|
||||
@Override public boolean remove(Object object) {
|
||||
if (!esDelegate.contains(object)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// safe because esDelgate.contains(object).
|
||||
Entry<?, ?> entry = (Entry<?, ?>) object;
|
||||
inverse.delegate.remove(entry.getValue());
|
||||
/*
|
||||
* Remove the mapping in inverse before removing from esDelegate because
|
||||
* if entry is part of esDelegate, entry might be invalidated after the
|
||||
* mapping is removed from esDelegate.
|
||||
*/
|
||||
esDelegate.remove(entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public Iterator<Entry<K, V>> iterator() {
|
||||
final Iterator<Entry<K, V>> iterator = esDelegate.iterator();
|
||||
return new Iterator<Entry<K, V>>() {
|
||||
Entry<K, V> entry;
|
||||
|
||||
@Override public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override public Entry<K, V> next() {
|
||||
entry = iterator.next();
|
||||
final Entry<K, V> finalEntry = entry;
|
||||
|
||||
return new ForwardingMapEntry<K, V>() {
|
||||
@Override protected Entry<K, V> delegate() {
|
||||
return finalEntry;
|
||||
}
|
||||
|
||||
@Override public V setValue(V value) {
|
||||
// Preconditions keep the map and inverse consistent.
|
||||
checkState(contains(this), "entry no longer in map");
|
||||
// similar to putInBothMaps, but set via entry
|
||||
if (Preconditions.equal(value, getValue())) {
|
||||
return value;
|
||||
}
|
||||
checkArgument(!containsValue(value),
|
||||
"value already present: %s", value);
|
||||
V oldValue = finalEntry.setValue(value);
|
||||
checkState(Preconditions.equal(value, get(getKey())),
|
||||
"entry no longer in map");
|
||||
updateInverseMap(getKey(), true, oldValue, value);
|
||||
return oldValue;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override public void remove() {
|
||||
checkRemove(entry != null);
|
||||
V value = entry.getValue();
|
||||
iterator.remove();
|
||||
removeFromInverseMap(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// See java.util.Collections.CheckedEntrySet for details on attacks.
|
||||
|
||||
@Override public Object[] toArray() {
|
||||
return standardToArray();
|
||||
}
|
||||
@Override public <T> T[] toArray(T[] array) {
|
||||
return standardToArray(array);
|
||||
}
|
||||
@Override public boolean contains(Object o) {
|
||||
return Maps.containsEntryImpl(delegate(), o);
|
||||
}
|
||||
@Override public boolean containsAll(Collection<?> c) {
|
||||
return standardContainsAll(c);
|
||||
}
|
||||
@Override public boolean removeAll(Collection<?> c) {
|
||||
return standardRemoveAll(c);
|
||||
}
|
||||
@Override public boolean retainAll(Collection<?> c) {
|
||||
return standardRetainAll(c);
|
||||
}
|
||||
}
|
||||
|
||||
/** The inverse of any other {@code AbstractBiMap} subclass. */
|
||||
private static class Inverse<K, V> extends AbstractBiMap<K, V> {
|
||||
private Inverse(Map<K, V> backward, AbstractBiMap<V, K> forward) {
|
||||
super(backward, forward);
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialization stores the forward bimap, the inverse of this inverse.
|
||||
* Deserialization calls inverse() on the forward bimap and returns that
|
||||
* inverse.
|
||||
*
|
||||
* If a bimap and its inverse are serialized together, the deserialized
|
||||
* instances have inverse() methods that return the other.
|
||||
*/
|
||||
|
||||
@Override
|
||||
K checkKey(K key) {
|
||||
return inverse.checkValue(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
V checkValue(V value) {
|
||||
return inverse.checkKey(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @serialData the forward bimap
|
||||
*/
|
||||
|
||||
private void writeObject(ObjectOutputStream stream) throws IOException {
|
||||
stream.defaultWriteObject();
|
||||
stream.writeObject(inverse());
|
||||
}
|
||||
|
||||
|
||||
// reading data stored by writeObject
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
setInverse((AbstractBiMap<V, K>) stream.readObject());
|
||||
}
|
||||
|
||||
|
||||
Object readResolve() {
|
||||
return inverse().inverse();
|
||||
}
|
||||
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
106
java/src/game/collect/AbstractIndexedListIterator.java
Normal file
106
java/src/game/collect/AbstractIndexedListIterator.java
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (C) 2009 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.Preconditions.checkPositionIndex;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* This class provides a skeletal implementation of the {@link ListIterator}
|
||||
* interface across a fixed number of elements that may be retrieved by
|
||||
* position. It does not support {@link #remove}, {@link #set}, or {@link #add}.
|
||||
*
|
||||
* @author Jared Levy
|
||||
*/
|
||||
|
||||
abstract class AbstractIndexedListIterator<E>
|
||||
extends UnmodifiableListIterator<E> {
|
||||
private final int size;
|
||||
private int position;
|
||||
|
||||
/**
|
||||
* Returns the element with the specified index. This method is called by
|
||||
* {@link #next()}.
|
||||
*/
|
||||
protected abstract E get(int index);
|
||||
|
||||
/**
|
||||
* Constructs an iterator across a sequence of the given size whose initial
|
||||
* position is 0. That is, the first call to {@link #next()} will return the
|
||||
* first element (or throw {@link NoSuchElementException} if {@code size} is
|
||||
* zero).
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code size} is negative
|
||||
*/
|
||||
protected AbstractIndexedListIterator(int size) {
|
||||
this(size, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an iterator across a sequence of the given size with the given
|
||||
* initial position. That is, the first call to {@link #nextIndex()} will
|
||||
* return {@code position}, and the first call to {@link #next()} will return
|
||||
* the element at that index, if available. Calls to {@link #previous()} can
|
||||
* retrieve the preceding {@code position} elements.
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if {@code position} is negative or is
|
||||
* greater than {@code size}
|
||||
* @throws IllegalArgumentException if {@code size} is negative
|
||||
*/
|
||||
protected AbstractIndexedListIterator(int size, int position) {
|
||||
checkPositionIndex(position, size);
|
||||
this.size = size;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasNext() {
|
||||
return position < size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final E next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
return get(position++);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int nextIndex() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasPrevious() {
|
||||
return position > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final E previous() {
|
||||
if (!hasPrevious()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
return get(--position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int previousIndex() {
|
||||
return position - 1;
|
||||
}
|
||||
}
|
173
java/src/game/collect/AbstractIterator.java
Normal file
173
java/src/game/collect/AbstractIterator.java
Normal file
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.Preconditions.checkState;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* This class provides a skeletal implementation of the {@code Iterator}
|
||||
* interface, to make this interface easier to implement for certain types of
|
||||
* data sources.
|
||||
*
|
||||
* <p>{@code Iterator} requires its implementations to support querying the
|
||||
* end-of-data status without changing the iterator's state, using the {@link
|
||||
* #hasNext} method. But many data sources, such as {@link
|
||||
* java.io.Reader#read()}, do not expose this information; the only way to
|
||||
* discover whether there is any data left is by trying to retrieve it. These
|
||||
* types of data sources are ordinarily difficult to write iterators for. But
|
||||
* using this class, one must implement only the {@link #computeNext} method,
|
||||
* and invoke the {@link #endOfData} method when appropriate.
|
||||
*
|
||||
* <p>Another example is an iterator that skips over null elements in a backing
|
||||
* iterator. This could be implemented as: <pre> {@code
|
||||
*
|
||||
* public static Iterator<String> skipNulls(final Iterator<String> in) {
|
||||
* return new AbstractIterator<String>() {
|
||||
* protected String computeNext() {
|
||||
* while (in.hasNext()) {
|
||||
* String s = in.next();
|
||||
* if (s != null) {
|
||||
* return s;
|
||||
* }
|
||||
* }
|
||||
* return endOfData();
|
||||
* }
|
||||
* };
|
||||
* }}</pre>
|
||||
*
|
||||
* <p>This class supports iterators that include null elements.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
// When making changes to this class, please also update the copy at
|
||||
// com.google.common.base.AbstractIterator
|
||||
|
||||
public abstract class AbstractIterator<T> extends UnmodifiableIterator<T> {
|
||||
private State state = State.NOT_READY;
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected AbstractIterator() {}
|
||||
|
||||
private enum State {
|
||||
/** We have computed the next element and haven't returned it yet. */
|
||||
READY,
|
||||
|
||||
/** We haven't yet computed or have already returned the element. */
|
||||
NOT_READY,
|
||||
|
||||
/** We have reached the end of the data and are finished. */
|
||||
DONE,
|
||||
|
||||
/** We've suffered an exception and are kaput. */
|
||||
FAILED,
|
||||
}
|
||||
|
||||
private T next;
|
||||
|
||||
/**
|
||||
* Returns the next element. <b>Note:</b> the implementation must call {@link
|
||||
* #endOfData()} when there are no elements left in the iteration. Failure to
|
||||
* do so could result in an infinite loop.
|
||||
*
|
||||
* <p>The initial invocation of {@link #hasNext()} or {@link #next()} calls
|
||||
* this method, as does the first invocation of {@code hasNext} or {@code
|
||||
* next} following each successful call to {@code next}. Once the
|
||||
* implementation either invokes {@code endOfData} or throws an exception,
|
||||
* {@code computeNext} is guaranteed to never be called again.
|
||||
*
|
||||
* <p>If this method throws an exception, it will propagate outward to the
|
||||
* {@code hasNext} or {@code next} invocation that invoked this method. Any
|
||||
* further attempts to use the iterator will result in an {@link
|
||||
* IllegalStateException}.
|
||||
*
|
||||
* <p>The implementation of this method may not invoke the {@code hasNext},
|
||||
* {@code next}, or {@link #peek()} methods on this instance; if it does, an
|
||||
* {@code IllegalStateException} will result.
|
||||
*
|
||||
* @return the next element if there was one. If {@code endOfData} was called
|
||||
* during execution, the return value will be ignored.
|
||||
* @throws RuntimeException if any unrecoverable error happens. This exception
|
||||
* will propagate outward to the {@code hasNext()}, {@code next()}, or
|
||||
* {@code peek()} invocation that invoked this method. Any further
|
||||
* attempts to use the iterator will result in an
|
||||
* {@link IllegalStateException}.
|
||||
*/
|
||||
protected abstract T computeNext();
|
||||
|
||||
/**
|
||||
* Implementations of {@link #computeNext} <b>must</b> invoke this method when
|
||||
* there are no elements left in the iteration.
|
||||
*
|
||||
* @return {@code null}; a convenience so your {@code computeNext}
|
||||
* implementation can use the simple statement {@code return endOfData();}
|
||||
*/
|
||||
protected final T endOfData() {
|
||||
state = State.DONE;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasNext() {
|
||||
checkState(state != State.FAILED);
|
||||
switch (state) {
|
||||
case DONE:
|
||||
return false;
|
||||
case READY:
|
||||
return true;
|
||||
default:
|
||||
}
|
||||
return tryToComputeNext();
|
||||
}
|
||||
|
||||
private boolean tryToComputeNext() {
|
||||
state = State.FAILED; // temporary pessimism
|
||||
next = computeNext();
|
||||
if (state != State.DONE) {
|
||||
state = State.READY;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
state = State.NOT_READY;
|
||||
T result = next;
|
||||
next = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next element in the iteration without advancing the iteration,
|
||||
* according to the contract of {@link PeekingIterator#peek()}.
|
||||
*
|
||||
* <p>Implementations of {@code AbstractIterator} that wish to expose this
|
||||
* functionality should implement {@code PeekingIterator}.
|
||||
*/
|
||||
public final T peek() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
return next;
|
||||
}
|
||||
}
|
62
java/src/game/collect/AbstractMapEntry.java
Normal file
62
java/src/game/collect/AbstractMapEntry.java
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Implementation of the {@code equals}, {@code hashCode}, and {@code toString}
|
||||
* methods of {@code Entry}.
|
||||
*
|
||||
* @author Jared Levy
|
||||
*/
|
||||
|
||||
abstract class AbstractMapEntry<K, V> implements Entry<K, V> {
|
||||
|
||||
@Override
|
||||
public abstract K getKey();
|
||||
|
||||
@Override
|
||||
public abstract V getValue();
|
||||
|
||||
@Override
|
||||
public V setValue(V value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object object) {
|
||||
if (object instanceof Entry) {
|
||||
Entry<?, ?> that = (Entry<?, ?>) object;
|
||||
return Preconditions.equal(this.getKey(), that.getKey())
|
||||
&& Preconditions.equal(this.getValue(), that.getValue());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
K k = getKey();
|
||||
V v = getValue();
|
||||
return ((k == null) ? 0 : k.hashCode()) ^ ((v == null) ? 0 : v.hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the form {@code {key}={value}}.
|
||||
*/
|
||||
@Override public String toString() {
|
||||
return getKey() + "=" + getValue();
|
||||
}
|
||||
}
|
223
java/src/game/collect/AbstractTable.java
Normal file
223
java/src/game/collect/AbstractTable.java
Normal file
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Copyright (C) 2013 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Skeletal, implementation-agnostic implementation of the {@link Table} interface.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
|
||||
abstract class AbstractTable<R, C, V> implements Table<R, C, V> {
|
||||
|
||||
@Override
|
||||
public boolean containsRow(Object rowKey) {
|
||||
return Maps.safeContainsKey(rowMap(), rowKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsColumn(Object columnKey) {
|
||||
return Maps.safeContainsKey(columnMap(), columnKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<R> rowKeySet() {
|
||||
return rowMap().keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<C> columnKeySet() {
|
||||
return columnMap().keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
for (Map<C, V> row : rowMap().values()) {
|
||||
if (row.containsValue(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object rowKey, Object columnKey) {
|
||||
Map<C, V> row = Maps.safeGet(rowMap(), rowKey);
|
||||
return row != null && Maps.safeContainsKey(row, columnKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object rowKey, Object columnKey) {
|
||||
Map<C, V> row = Maps.safeGet(rowMap(), rowKey);
|
||||
return (row == null) ? null : Maps.safeGet(row, columnKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
Iterators.clear(cellSet().iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object rowKey, Object columnKey) {
|
||||
Map<C, V> row = Maps.safeGet(rowMap(), rowKey);
|
||||
return (row == null) ? null : Maps.safeRemove(row, columnKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(R rowKey, C columnKey, V value) {
|
||||
return row(rowKey).put(columnKey, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Table<? extends R, ? extends C, ? extends V> table) {
|
||||
for (Table.Cell<? extends R, ? extends C, ? extends V> cell : table.cellSet()) {
|
||||
put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private transient Set<Cell<R, C, V>> cellSet;
|
||||
|
||||
@Override
|
||||
public Set<Cell<R, C, V>> cellSet() {
|
||||
Set<Cell<R, C, V>> result = cellSet;
|
||||
return (result == null) ? cellSet = createCellSet() : result;
|
||||
}
|
||||
|
||||
Set<Cell<R, C, V>> createCellSet() {
|
||||
return new CellSet();
|
||||
}
|
||||
|
||||
abstract Iterator<Table.Cell<R, C, V>> cellIterator();
|
||||
|
||||
class CellSet extends AbstractSet<Cell<R, C, V>> {
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
if (o instanceof Cell) {
|
||||
Cell<?, ?, ?> cell = (Cell<?, ?, ?>) o;
|
||||
Map<C, V> row = Maps.safeGet(rowMap(), cell.getRowKey());
|
||||
return row != null && Filter.safeContains(
|
||||
row.entrySet(), Maps.immutableEntry(cell.getColumnKey(), cell.getValue()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
if (o instanceof Cell) {
|
||||
Cell<?, ?, ?> cell = (Cell<?, ?, ?>) o;
|
||||
Map<C, V> row = Maps.safeGet(rowMap(), cell.getRowKey());
|
||||
return row != null && Filter.safeRemove(
|
||||
row.entrySet(), Maps.immutableEntry(cell.getColumnKey(), cell.getValue()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
AbstractTable.this.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Table.Cell<R, C, V>> iterator() {
|
||||
return cellIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return AbstractTable.this.size();
|
||||
}
|
||||
}
|
||||
|
||||
private transient Collection<V> values;
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
Collection<V> result = values;
|
||||
return (result == null) ? values = createValues() : result;
|
||||
}
|
||||
|
||||
Collection<V> createValues() {
|
||||
return new Values();
|
||||
}
|
||||
|
||||
Iterator<V> valuesIterator() {
|
||||
return new TransformedIterator<Cell<R, C, V>, V>(cellSet().iterator()) {
|
||||
@Override
|
||||
V transform(Cell<R, C, V> cell) {
|
||||
return cell.getValue();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class Values extends AbstractCollection<V> {
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
return valuesIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return containsValue(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
AbstractTable.this.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return AbstractTable.this.size();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object obj) {
|
||||
return equalsImpl(this, obj);
|
||||
}
|
||||
|
||||
static boolean equalsImpl(Table<?, ?, ?> table, Object obj) {
|
||||
if (obj == table) {
|
||||
return true;
|
||||
} else if (obj instanceof Table) {
|
||||
Table<?, ?, ?> that = (Table<?, ?, ?>) obj;
|
||||
return table.cellSet().equals(that.cellSet());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
return cellSet().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string representation {@code rowMap().toString()}.
|
||||
*/
|
||||
@Override public String toString() {
|
||||
return rowMap().toString();
|
||||
}
|
||||
}
|
106
java/src/game/collect/BiMap.java
Normal file
106
java/src/game/collect/BiMap.java
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A bimap (or "bidirectional map") is a map that preserves the uniqueness of
|
||||
* its values as well as that of its keys. This constraint enables bimaps to
|
||||
* support an "inverse view", which is another bimap containing the same entries
|
||||
* as this bimap but with reversed keys and values.
|
||||
*
|
||||
* <p>See the Guava User Guide article on <a href=
|
||||
* "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#BiMap">
|
||||
* {@code BiMap}</a>.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
|
||||
public interface BiMap<K, V> extends Map<K, V> {
|
||||
// Modification Operations
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws IllegalArgumentException if the given value is already bound to a
|
||||
* different key in this bimap. The bimap will remain unmodified in this
|
||||
* event. To avoid this exception, call {@link #forcePut} instead.
|
||||
*/
|
||||
@Override
|
||||
V put(K key, V value);
|
||||
|
||||
/**
|
||||
* An alternate form of {@code put} that silently removes any existing entry
|
||||
* with the value {@code value} before proceeding with the {@link #put}
|
||||
* operation. If the bimap previously contained the provided key-value
|
||||
* mapping, this method has no effect.
|
||||
*
|
||||
* <p>Note that a successful call to this method could cause the size of the
|
||||
* bimap to increase by one, stay the same, or even decrease by one.
|
||||
*
|
||||
* <p><b>Warning:</b> If an existing entry with this value is removed, the key
|
||||
* for that entry is discarded and not returned.
|
||||
*
|
||||
* @param key the key with which the specified value is to be associated
|
||||
* @param value the value to be associated with the specified key
|
||||
* @return the value which was previously associated with the key, which may
|
||||
* be {@code null}, or {@code null} if there was no previous entry
|
||||
*/
|
||||
V forcePut(K key, V value);
|
||||
|
||||
// Bulk Operations
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p><b>Warning:</b> the results of calling this method may vary depending on
|
||||
* the iteration order of {@code map}.
|
||||
*
|
||||
* @throws IllegalArgumentException if an attempt to {@code put} any
|
||||
* entry fails. Note that some map entries may have been added to the
|
||||
* bimap before the exception was thrown.
|
||||
*/
|
||||
@Override
|
||||
void putAll(Map<? extends K, ? extends V> map);
|
||||
|
||||
// Views
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>Because a bimap has unique values, this method returns a {@link Set},
|
||||
* instead of the {@link java.util.Collection} specified in the {@link Map}
|
||||
* interface.
|
||||
*/
|
||||
@Override
|
||||
Set<V> values();
|
||||
|
||||
/**
|
||||
* Returns the inverse view of this bimap, which maps each of this bimap's
|
||||
* values to its associated key. The two bimaps are backed by the same data;
|
||||
* any changes to one will appear in the other.
|
||||
*
|
||||
* <p><b>Note:</b>There is no guaranteed correspondence between the iteration
|
||||
* order of a bimap and that of its inverse.
|
||||
*
|
||||
* @return the inverse view of this bimap
|
||||
*/
|
||||
BiMap<V, K> inverse();
|
||||
}
|
49
java/src/game/collect/CollectPreconditions.java
Normal file
49
java/src/game/collect/CollectPreconditions.java
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.Preconditions.checkState;
|
||||
|
||||
/**
|
||||
* Precondition checks useful in collection implementations.
|
||||
*/
|
||||
|
||||
final class CollectPreconditions {
|
||||
|
||||
static void checkEntryNotNull(Object key, Object value) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("null key in entry: null=" + value);
|
||||
} else if (value == null) {
|
||||
throw new NullPointerException("null value in entry: " + key + "=null");
|
||||
}
|
||||
}
|
||||
|
||||
static int checkNonnegative(int value, String name) {
|
||||
if (value < 0) {
|
||||
throw new IllegalArgumentException(name + " cannot be negative but was: " + value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Precondition tester for {@code Iterator.remove()} that throws an exception with a consistent
|
||||
* error message.
|
||||
*/
|
||||
static void checkRemove(boolean canRemove) {
|
||||
checkState(canRemove, "no calls to next() since the last call to remove()");
|
||||
}
|
||||
}
|
273
java/src/game/collect/DenseImmutableTable.java
Normal file
273
java/src/game/collect/DenseImmutableTable.java
Normal file
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* Copyright (C) 2009 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.Preconditions.checkArgument;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A {@code RegularImmutableTable} optimized for dense data.
|
||||
*/
|
||||
|
||||
//@Immutable
|
||||
final class DenseImmutableTable<R, C, V>
|
||||
extends RegularImmutableTable<R, C, V> {
|
||||
private final ImmutableMap<R, Integer> rowKeyToIndex;
|
||||
private final ImmutableMap<C, Integer> columnKeyToIndex;
|
||||
private final ImmutableMap<R, Map<C, V>> rowMap;
|
||||
private final ImmutableMap<C, Map<R, V>> columnMap;
|
||||
private final int[] rowCounts;
|
||||
private final int[] columnCounts;
|
||||
private final V[][] values;
|
||||
private final int[] iterationOrderRow;
|
||||
private final int[] iterationOrderColumn;
|
||||
|
||||
private static <E> ImmutableMap<E, Integer> makeIndex(ImmutableSet<E> set) {
|
||||
ImmutableMap.Builder<E, Integer> indexBuilder = ImmutableMap.builder();
|
||||
int i = 0;
|
||||
for (E key : set) {
|
||||
indexBuilder.put(key, i);
|
||||
i++;
|
||||
}
|
||||
return indexBuilder.build();
|
||||
}
|
||||
|
||||
DenseImmutableTable(ImmutableList<Cell<R, C, V>> cellList,
|
||||
ImmutableSet<R> rowSpace, ImmutableSet<C> columnSpace) {
|
||||
|
||||
V[][] array = (V[][]) new Object[rowSpace.size()][columnSpace.size()];
|
||||
this.values = array;
|
||||
this.rowKeyToIndex = makeIndex(rowSpace);
|
||||
this.columnKeyToIndex = makeIndex(columnSpace);
|
||||
rowCounts = new int[rowKeyToIndex.size()];
|
||||
columnCounts = new int[columnKeyToIndex.size()];
|
||||
int[] iterationOrderRow = new int[cellList.size()];
|
||||
int[] iterationOrderColumn = new int[cellList.size()];
|
||||
for (int i = 0; i < cellList.size(); i++) {
|
||||
Cell<R, C, V> cell = cellList.get(i);
|
||||
R rowKey = cell.getRowKey();
|
||||
C columnKey = cell.getColumnKey();
|
||||
int rowIndex = rowKeyToIndex.get(rowKey);
|
||||
int columnIndex = columnKeyToIndex.get(columnKey);
|
||||
V existingValue = values[rowIndex][columnIndex];
|
||||
checkArgument(existingValue == null, "duplicate key: (%s, %s)", rowKey, columnKey);
|
||||
values[rowIndex][columnIndex] = cell.getValue();
|
||||
rowCounts[rowIndex]++;
|
||||
columnCounts[columnIndex]++;
|
||||
iterationOrderRow[i] = rowIndex;
|
||||
iterationOrderColumn[i] = columnIndex;
|
||||
}
|
||||
this.iterationOrderRow = iterationOrderRow;
|
||||
this.iterationOrderColumn = iterationOrderColumn;
|
||||
this.rowMap = new RowMap();
|
||||
this.columnMap = new ColumnMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* An immutable map implementation backed by an indexed nullable array.
|
||||
*/
|
||||
private abstract static class ImmutableArrayMap<K, V> extends ImmutableMap<K, V> {
|
||||
private final int size;
|
||||
|
||||
ImmutableArrayMap(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
abstract ImmutableMap<K, Integer> keyToIndex();
|
||||
|
||||
// True if getValue never returns null.
|
||||
private boolean isFull() {
|
||||
return size == keyToIndex().size();
|
||||
}
|
||||
|
||||
K getKey(int index) {
|
||||
return keyToIndex().keySet().asList().get(index);
|
||||
}
|
||||
|
||||
abstract V getValue(int keyIndex);
|
||||
|
||||
@Override
|
||||
ImmutableSet<K> createKeySet() {
|
||||
return isFull() ? keyToIndex().keySet() : super.createKeySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
Integer keyIndex = keyToIndex().get(key);
|
||||
return (keyIndex == null) ? null : getValue(keyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableSet<Entry<K, V>> createEntrySet() {
|
||||
return new ImmutableMapEntrySet<K, V>() {
|
||||
@Override ImmutableMap<K, V> map() {
|
||||
return ImmutableArrayMap.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnmodifiableIterator<Entry<K, V>> iterator() {
|
||||
return new AbstractIterator<Entry<K, V>>() {
|
||||
private int index = -1;
|
||||
private final int maxIndex = keyToIndex().size();
|
||||
|
||||
@Override
|
||||
protected Entry<K, V> computeNext() {
|
||||
for (index++; index < maxIndex; index++) {
|
||||
V value = getValue(index);
|
||||
if (value != null) {
|
||||
return Maps.immutableEntry(getKey(index), value);
|
||||
}
|
||||
}
|
||||
return endOfData();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private final class Row extends ImmutableArrayMap<C, V> {
|
||||
private final int rowIndex;
|
||||
|
||||
Row(int rowIndex) {
|
||||
super(rowCounts[rowIndex]);
|
||||
this.rowIndex = rowIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableMap<C, Integer> keyToIndex() {
|
||||
return columnKeyToIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
V getValue(int keyIndex) {
|
||||
return values[rowIndex][keyIndex];
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private final class Column extends ImmutableArrayMap<R, V> {
|
||||
private final int columnIndex;
|
||||
|
||||
Column(int columnIndex) {
|
||||
super(columnCounts[columnIndex]);
|
||||
this.columnIndex = columnIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableMap<R, Integer> keyToIndex() {
|
||||
return rowKeyToIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
V getValue(int keyIndex) {
|
||||
return values[keyIndex][columnIndex];
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private final class RowMap extends ImmutableArrayMap<R, Map<C, V>> {
|
||||
private RowMap() {
|
||||
super(rowCounts.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableMap<R, Integer> keyToIndex() {
|
||||
return rowKeyToIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
Map<C, V> getValue(int keyIndex) {
|
||||
return new Row(keyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private final class ColumnMap extends ImmutableArrayMap<C, Map<R, V>> {
|
||||
private ColumnMap() {
|
||||
super(columnCounts.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableMap<C, Integer> keyToIndex() {
|
||||
return columnKeyToIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
Map<R, V> getValue(int keyIndex) {
|
||||
return new Column(keyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public ImmutableMap<C, Map<R, V>> columnMap() {
|
||||
return columnMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableMap<R, Map<C, V>> rowMap() {
|
||||
return rowMap;
|
||||
}
|
||||
|
||||
@Override public V get(Object rowKey,
|
||||
Object columnKey) {
|
||||
Integer rowIndex = rowKeyToIndex.get(rowKey);
|
||||
Integer columnIndex = columnKeyToIndex.get(columnKey);
|
||||
return ((rowIndex == null) || (columnIndex == null)) ? null
|
||||
: values[rowIndex][columnIndex];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return iterationOrderRow.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
Cell<R, C, V> getCell(int index) {
|
||||
int rowIndex = iterationOrderRow[index];
|
||||
int columnIndex = iterationOrderColumn[index];
|
||||
R rowKey = rowKeySet().asList().get(rowIndex);
|
||||
C columnKey = columnKeySet().asList().get(columnIndex);
|
||||
V value = values[rowIndex][columnIndex];
|
||||
return cellOf(rowKey, columnKey, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
V getValue(int index) {
|
||||
return values[iterationOrderRow[index]][iterationOrderColumn[index]];
|
||||
}
|
||||
}
|
304
java/src/game/collect/EmptyImmutableMap.java
Normal file
304
java/src/game/collect/EmptyImmutableMap.java
Normal file
|
@ -0,0 +1,304 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
/**
|
||||
* Bimap with no mappings.
|
||||
*
|
||||
* @author Jared Levy
|
||||
*/
|
||||
|
||||
// // uses writeReplace(), not default serialization
|
||||
final class EmptyImmutableMap extends ImmutableMap<Object, Object> {
|
||||
static final EmptyImmutableMap INSTANCE = new EmptyImmutableMap();
|
||||
|
||||
private EmptyImmutableMap() {}
|
||||
|
||||
// @Override public ImmutableBiMap<Object, Object> inverse() {
|
||||
// return this;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSet<Entry<Object, Object>> entrySet() {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableSet<Entry<Object, Object>> createEntrySet() {
|
||||
throw new AssertionError("should never be called");
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public ImmutableSetMultimap<Object, Object> asMultimap() {
|
||||
// return ImmutableSetMultimap.of();
|
||||
// }
|
||||
|
||||
@Override
|
||||
public ImmutableSet<Object> keySet() {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Object readResolve() {
|
||||
// return INSTANCE; // preserve singleton property
|
||||
// }
|
||||
/**
|
||||
* Returns the empty bimap.
|
||||
*/
|
||||
// Casting to any type is safe because the set will never hold any elements.
|
||||
//
|
||||
// public static <K, V> ImmutableBiMap<K, V> of() {
|
||||
// return (ImmutableBiMap<K, V>) EmptyImmutableBiMap.INSTANCE;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns an immutable bimap containing a single entry.
|
||||
*/
|
||||
// public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1) {
|
||||
// return new SingletonImmutableBiMap<K, V>(k1, v1);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing the given entries, in order.
|
||||
*
|
||||
* @throws IllegalArgumentException if duplicate keys or values are added
|
||||
*/
|
||||
// public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2) {
|
||||
// return new RegularImmutableBiMap<K, V>(entryOf(k1, v1), entryOf(k2, v2));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Returns an immutable map containing the given entries, in order.
|
||||
// *
|
||||
// * @throws IllegalArgumentException if duplicate keys or values are added
|
||||
// */
|
||||
// public static <K, V> ImmutableBiMap<K, V> of(
|
||||
// K k1, V v1, K k2, V v2, K k3, V v3) {
|
||||
// return new RegularImmutableBiMap<K, V>(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Returns an immutable map containing the given entries, in order.
|
||||
// *
|
||||
// * @throws IllegalArgumentException if duplicate keys or values are added
|
||||
// */
|
||||
// public static <K, V> ImmutableBiMap<K, V> of(
|
||||
// K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
|
||||
// return new RegularImmutableBiMap<K, V>(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3),
|
||||
// entryOf(k4, v4));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Returns an immutable map containing the given entries, in order.
|
||||
// *
|
||||
// * @throws IllegalArgumentException if duplicate keys or values are added
|
||||
// */
|
||||
// public static <K, V> ImmutableBiMap<K, V> of(
|
||||
// K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
|
||||
// return new RegularImmutableBiMap<K, V>(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3),
|
||||
// entryOf(k4, v4), entryOf(k5, v5));
|
||||
// }
|
||||
|
||||
// looking for of() with > 5 entries? Use the builder instead.
|
||||
|
||||
/**
|
||||
* Returns a new builder. The generated builder is equivalent to the builder
|
||||
* created by the {@link Builder} constructor.
|
||||
*/
|
||||
// public static <K, V> Builder<K, V> builder() {
|
||||
// return new Builder<K, V>();
|
||||
// }
|
||||
|
||||
/**
|
||||
* A builder for creating immutable bimap instances, especially {@code public
|
||||
* static final} bimaps ("constant bimaps"). Example: <pre> {@code
|
||||
*
|
||||
* static final ImmutableBiMap<String, Integer> WORD_TO_INT =
|
||||
* new ImmutableBiMap.Builder<String, Integer>()
|
||||
* .put("one", 1)
|
||||
* .put("two", 2)
|
||||
* .put("three", 3)
|
||||
* .build();}</pre>
|
||||
*
|
||||
* <p>For <i>small</i> immutable bimaps, the {@code ImmutableBiMap.of()} methods
|
||||
* are even more convenient.
|
||||
*
|
||||
* <p>Builder instances can be reused - it is safe to call {@link #build}
|
||||
* multiple times to build multiple bimaps in series. Each bimap is a superset
|
||||
* of the bimaps created before it.
|
||||
*
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
// public static final class Builder<K, V> extends ImmutableMap.Builder<K, V> {
|
||||
//
|
||||
// /**
|
||||
// * Creates a new builder. The returned builder is equivalent to the builder
|
||||
// * generated by {@link ImmutableBiMap#builder}.
|
||||
// */
|
||||
// public Builder() {}
|
||||
//
|
||||
// /**
|
||||
// * Associates {@code key} with {@code value} in the built bimap. Duplicate
|
||||
// * keys or values are not allowed, and will cause {@link #build} to fail.
|
||||
// */
|
||||
// @Override public Builder<K, V> put(K key, V value) {
|
||||
// super.put(key, value);
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Associates all of the given map's keys and values in the built bimap.
|
||||
// * Duplicate keys or values are not allowed, and will cause {@link #build}
|
||||
// * to fail.
|
||||
// *
|
||||
// * @throws NullPointerException if any key or value in {@code map} is null
|
||||
// */
|
||||
// @Override public Builder<K, V> putAll(Map<? extends K, ? extends V> map) {
|
||||
// super.putAll(map);
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Returns a newly-created immutable bimap.
|
||||
// *
|
||||
// * @throws IllegalArgumentException if duplicate keys or values were added
|
||||
// */
|
||||
// @Override public ImmutableBiMap<K, V> build() {
|
||||
// switch (size) {
|
||||
// case 0:
|
||||
// return of();
|
||||
// case 1:
|
||||
// return of(entries[0].getKey(), entries[0].getValue());
|
||||
// default:
|
||||
// return new RegularImmutableBiMap<K, V>(size, entries);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns an immutable bimap containing the same entries as {@code map}. If
|
||||
* {@code map} somehow contains entries with duplicate keys (for example, if
|
||||
* it is a {@code SortedMap} whose comparator is not <i>consistent with
|
||||
* equals</i>), the results of this method are undefined.
|
||||
*
|
||||
* <p>Despite the method name, this method attempts to avoid actually copying
|
||||
* the data when it is safe to do so. The exact circumstances under which a
|
||||
* copy will or will not be performed are undocumented and subject to change.
|
||||
*
|
||||
* @throws IllegalArgumentException if two keys have the same value
|
||||
* @throws NullPointerException if any key or value in {@code map} is null
|
||||
*/
|
||||
// public static <K, V> ImmutableBiMap<K, V> copyOf(
|
||||
// Map<? extends K, ? extends V> map) {
|
||||
// if (map instanceof ImmutableBiMap) {
|
||||
// // safe since map is not writable
|
||||
// ImmutableBiMap<K, V> bimap = (ImmutableBiMap<K, V>) map;
|
||||
// // TODO(user): if we need to make a copy of a BiMap because the
|
||||
// // forward map is a view, don't make a copy of the non-view delegate map
|
||||
// if (!bimap.isPartialView()) {
|
||||
// return bimap;
|
||||
// }
|
||||
// }
|
||||
// Entry<?, ?>[] entries = map.entrySet().toArray(EMPTY_ENTRY_ARRAY);
|
||||
// switch (entries.length) {
|
||||
// case 0:
|
||||
// return of();
|
||||
// case 1:
|
||||
// // safe covariant cast in this context
|
||||
// Entry<K, V> entry = (Entry<K, V>) entries[0];
|
||||
// return of(entry.getKey(), entry.getValue());
|
||||
// default:
|
||||
// return new RegularImmutableBiMap<K, V>(entries);
|
||||
// }
|
||||
// }
|
||||
|
||||
// private static final Entry<?, ?>[] EMPTY_ENTRY_ARRAY = new Entry<?, ?>[0];
|
||||
|
||||
// ImmutableBiMap() {}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The inverse of an {@code ImmutableBiMap} is another
|
||||
* {@code ImmutableBiMap}.
|
||||
*/
|
||||
// @Override
|
||||
// public abstract ImmutableBiMap<V, K> inverse();
|
||||
|
||||
/**
|
||||
* Returns an immutable set of the values in this map. The values are in the
|
||||
* same order as the parameters used to build this map.
|
||||
*/
|
||||
@Override public ImmutableSet<Object> values() {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the bimap unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
// @Deprecated
|
||||
// @Override
|
||||
// public V forcePut(K key, V value) {
|
||||
// throw new UnsupportedOperationException();
|
||||
// }
|
||||
|
||||
/**
|
||||
* Serialized type for all ImmutableBiMap instances. It captures the logical
|
||||
* contents and they are reconstructed using public factory methods. This
|
||||
* ensures that the implementation types remain as implementation details.
|
||||
*
|
||||
* Since the bimap is immutable, ImmutableBiMap doesn't require special logic
|
||||
* for keeping the bimap and its inverse in sync during serialization, the way
|
||||
* AbstractBiMap does.
|
||||
*/
|
||||
// private static class SerializedForm extends ImmutableMap.SerializedForm {
|
||||
// SerializedForm(ImmutableBiMap<?, ?> bimap) {
|
||||
// super(bimap);
|
||||
// }
|
||||
// @Override Object readResolve() {
|
||||
// Builder<Object, Object> builder = new Builder<Object, Object>();
|
||||
// return createMap(builder);
|
||||
// }
|
||||
// private static final long serialVersionUID = 0;
|
||||
// }
|
||||
//
|
||||
// @Override Object writeReplace() {
|
||||
// return new SerializedForm(this);
|
||||
// }
|
||||
}
|
93
java/src/game/collect/EmptyImmutableSet.java
Normal file
93
java/src/game/collect/EmptyImmutableSet.java
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* An empty immutable set.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
*/
|
||||
|
||||
final class EmptyImmutableSet extends ImmutableSet<Object> {
|
||||
static final EmptyImmutableSet INSTANCE = new EmptyImmutableSet();
|
||||
|
||||
private EmptyImmutableSet() {}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean contains(Object target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean containsAll(Collection<?> targets) {
|
||||
return targets.isEmpty();
|
||||
}
|
||||
|
||||
@Override public UnmodifiableIterator<Object> iterator() {
|
||||
return Iterators.emptyIterator();
|
||||
}
|
||||
|
||||
@Override boolean isPartialView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
int copyIntoArray(Object[] dst, int offset) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<Object> asList() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object object) {
|
||||
if (object instanceof Set) {
|
||||
Set<?> that = (Set<?>) object;
|
||||
return that.isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public final int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override boolean isHashCodeFast() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "[]";
|
||||
}
|
||||
|
||||
Object readResolve() {
|
||||
return INSTANCE; // preserve singleton property
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
659
java/src/game/collect/Filter.java
Normal file
659
java/src/game/collect/Filter.java
Normal file
|
@ -0,0 +1,659 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.Preconditions.checkArgument;
|
||||
import static game.collect.Preconditions.checkNotNull;
|
||||
import static game.util.Predicates.and;
|
||||
import static game.util.Predicates.in;
|
||||
import static game.util.Predicates.not;
|
||||
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import game.util.Predicates;
|
||||
|
||||
/**
|
||||
* Provides static methods for working with {@code Collection} instances.
|
||||
*
|
||||
* @author Chris Povirk
|
||||
* @author Mike Bostock
|
||||
* @author Jared Levy
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
|
||||
public final class Filter {
|
||||
private Filter() {}
|
||||
|
||||
/**
|
||||
* Returns the elements of {@code unfiltered} that satisfy a predicate. The
|
||||
* returned collection is a live view of {@code unfiltered}; changes to one
|
||||
* affect the other.
|
||||
*
|
||||
* <p>The resulting collection's iterator does not support {@code remove()},
|
||||
* but all other collection methods are supported. When given an element that
|
||||
* doesn't satisfy the predicate, the collection's {@code add()} and {@code
|
||||
* addAll()} methods throw an {@link IllegalArgumentException}. When methods
|
||||
* such as {@code removeAll()} and {@code clear()} are called on the filtered
|
||||
* collection, only elements that satisfy the filter will be removed from the
|
||||
* underlying collection.
|
||||
*
|
||||
* <p>The returned collection isn't threadsafe or serializable, even if
|
||||
* {@code unfiltered} is.
|
||||
*
|
||||
* <p>Many of the filtered collection's methods, such as {@code size()},
|
||||
* iterate across every element in the underlying collection and determine
|
||||
* which elements satisfy the filter. When a live view is <i>not</i> needed,
|
||||
* it may be faster to copy {@code Iterables.filter(unfiltered, predicate)}
|
||||
* and use the copy.
|
||||
*
|
||||
* <p><b>Warning:</b> {@code predicate} must be <i>consistent with equals</i>,
|
||||
* as documented at {@link Predicate#apply}. Do not provide a predicate such
|
||||
* as {@code Predicates.instanceOf(ArrayList.class)}, which is inconsistent
|
||||
* with equals. (See {@link Iterables#filter(Iterable, Class)} for related
|
||||
* functionality.)
|
||||
*/
|
||||
// TODO(kevinb): how can we omit that Iterables link when building gwt
|
||||
// javadoc?
|
||||
public static <E> Collection<E> filter(
|
||||
Collection<E> unfiltered, Predicate<? super E> predicate) {
|
||||
if (unfiltered instanceof FilteredCollection) {
|
||||
// Support clear(), removeAll(), and retainAll() when filtering a filtered
|
||||
// collection.
|
||||
return ((FilteredCollection<E>) unfiltered).createCombined(predicate);
|
||||
}
|
||||
|
||||
return new FilteredCollection<E>(
|
||||
checkNotNull(unfiltered), checkNotNull(predicate));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link Collection#contains}. Returns {@code false} if the
|
||||
* {@code contains} method throws a {@code ClassCastException} or
|
||||
* {@code NullPointerException}.
|
||||
*/
|
||||
static boolean safeContains(
|
||||
Collection<?> collection, Object object) {
|
||||
checkNotNull(collection);
|
||||
try {
|
||||
return collection.contains(object);
|
||||
} catch (ClassCastException e) {
|
||||
return false;
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link Collection#remove}. Returns {@code false} if the
|
||||
* {@code remove} method throws a {@code ClassCastException} or
|
||||
* {@code NullPointerException}.
|
||||
*/
|
||||
static boolean safeRemove(Collection<?> collection, Object object) {
|
||||
checkNotNull(collection);
|
||||
try {
|
||||
return collection.remove(object);
|
||||
} catch (ClassCastException e) {
|
||||
return false;
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static class FilteredCollection<E> extends AbstractCollection<E> {
|
||||
final Collection<E> unfiltered;
|
||||
final Predicate<? super E> predicate;
|
||||
|
||||
FilteredCollection(Collection<E> unfiltered,
|
||||
Predicate<? super E> predicate) {
|
||||
this.unfiltered = unfiltered;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
FilteredCollection<E> createCombined(Predicate<? super E> newPredicate) {
|
||||
return new FilteredCollection<E>(unfiltered,
|
||||
Predicates.<E>and(predicate, newPredicate));
|
||||
// .<E> above needed to compile in JDK 5
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E element) {
|
||||
checkArgument(predicate.test(element));
|
||||
return unfiltered.add(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> collection) {
|
||||
for (E element : collection) {
|
||||
checkArgument(predicate.test(element));
|
||||
}
|
||||
return unfiltered.addAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
Iterables.removeIf(unfiltered, predicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object element) {
|
||||
if (safeContains(unfiltered, element)) {
|
||||
// element is in unfiltered, so it must be an E
|
||||
E e = (E) element;
|
||||
return predicate.test(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> collection) {
|
||||
return containsAllImpl(this, collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return !Iterables.any(unfiltered, predicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return Iterators.filter(unfiltered.iterator(), predicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object element) {
|
||||
return contains(element) && unfiltered.remove(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(final Collection<?> collection) {
|
||||
return Iterables.removeIf(unfiltered, and(predicate, in(collection)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(final Collection<?> collection) {
|
||||
return Iterables.removeIf(unfiltered, and(predicate, not(in(collection))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return Iterators.size(iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
// creating an ArrayList so filtering happens once
|
||||
return Lists.newArrayList(iterator()).toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] array) {
|
||||
return Lists.newArrayList(iterator()).toArray(array);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection that applies {@code function} to each element of
|
||||
* {@code fromCollection}. The returned collection is a live view of {@code
|
||||
* fromCollection}; changes to one affect the other.
|
||||
*
|
||||
* <p>The returned collection's {@code add()} and {@code addAll()} methods
|
||||
* throw an {@link UnsupportedOperationException}. All other collection
|
||||
* methods are supported, as long as {@code fromCollection} supports them.
|
||||
*
|
||||
* <p>The returned collection isn't threadsafe or serializable, even if
|
||||
* {@code fromCollection} is.
|
||||
*
|
||||
* <p>When a live view is <i>not</i> needed, it may be faster to copy the
|
||||
* transformed collection and use the copy.
|
||||
*
|
||||
* <p>If the input {@code Collection} is known to be a {@code List}, consider
|
||||
* {@link Lists#transform}. If only an {@code Iterable} is available, use
|
||||
* {@link Iterables#transform}.
|
||||
*/
|
||||
// public static <F, T> Collection<T> transform(Collection<F> fromCollection,
|
||||
// Function<? super F, T> function) {
|
||||
// return new TransformedCollection<F, T>(fromCollection, function);
|
||||
// }
|
||||
//
|
||||
// static class TransformedCollection<F, T> extends AbstractCollection<T> {
|
||||
// final Collection<F> fromCollection;
|
||||
// final Function<? super F, ? extends T> function;
|
||||
//
|
||||
// TransformedCollection(Collection<F> fromCollection,
|
||||
// Function<? super F, ? extends T> function) {
|
||||
// this.fromCollection = checkNotNull(fromCollection);
|
||||
// this.function = checkNotNull(function);
|
||||
// }
|
||||
//
|
||||
// @Override public void clear() {
|
||||
// fromCollection.clear();
|
||||
// }
|
||||
//
|
||||
// @Override public boolean isEmpty() {
|
||||
// return fromCollection.isEmpty();
|
||||
// }
|
||||
//
|
||||
// @Override public Iterator<T> iterator() {
|
||||
// return Iterators.transform(fromCollection.iterator(), function);
|
||||
// }
|
||||
//
|
||||
// @Override public int size() {
|
||||
// return fromCollection.size();
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the collection {@code self} contains all of the
|
||||
* elements in the collection {@code c}.
|
||||
*
|
||||
* <p>This method iterates over the specified collection {@code c}, checking
|
||||
* each element returned by the iterator in turn to see if it is contained in
|
||||
* the specified collection {@code self}. If all elements are so contained,
|
||||
* {@code true} is returned, otherwise {@code false}.
|
||||
*
|
||||
* @param self a collection which might contain all elements in {@code c}
|
||||
* @param c a collection whose elements might be contained by {@code self}
|
||||
*/
|
||||
static boolean containsAllImpl(Collection<?> self, Collection<?> c) {
|
||||
return Iterables.all(c, Predicates.in(self));
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of {@link Collection#toString()}.
|
||||
*/
|
||||
// static String toStringImpl(final Collection<?> collection) {
|
||||
// StringBuilder sb
|
||||
// = newStringBuilderForCollection(collection.size()).append('[');
|
||||
// STANDARD_JOINER.appendTo(
|
||||
// sb, Iterables.transform(collection, new Function<Object, Object>() {
|
||||
// @Override public Object apply(Object input) {
|
||||
// return input == collection ? "(this Collection)" : input;
|
||||
// }
|
||||
// }));
|
||||
// return sb.append(']').toString();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Returns best-effort-sized StringBuilder based on the given collection size.
|
||||
// */
|
||||
// static StringBuilder newStringBuilderForCollection(int size) {
|
||||
// checkNonnegative(size, "size");
|
||||
// return new StringBuilder((int) Math.min(size * 8L, Ints.MAX_POWER_OF_TWO));
|
||||
// }
|
||||
|
||||
/**
|
||||
* Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557
|
||||
*/
|
||||
static <T> Collection<T> cast(Iterable<T> iterable) {
|
||||
return (Collection<T>) iterable;
|
||||
}
|
||||
|
||||
// static final Joiner STANDARD_JOINER = Joiner.on(", ").useForNull("null");
|
||||
|
||||
/**
|
||||
* Returns a {@link Collection} of all the permutations of the specified
|
||||
* {@link Iterable}.
|
||||
*
|
||||
* <p><i>Notes:</i> This is an implementation of the algorithm for
|
||||
* Lexicographical Permutations Generation, described in Knuth's "The Art of
|
||||
* Computer Programming", Volume 4, Chapter 7, Section 7.2.1.2. The
|
||||
* iteration order follows the lexicographical order. This means that
|
||||
* the first permutation will be in ascending order, and the last will be in
|
||||
* descending order.
|
||||
*
|
||||
* <p>Duplicate elements are considered equal. For example, the list [1, 1]
|
||||
* will have only one permutation, instead of two. This is why the elements
|
||||
* have to implement {@link Comparable}.
|
||||
*
|
||||
* <p>An empty iterable has only one permutation, which is an empty list.
|
||||
*
|
||||
* <p>This method is equivalent to
|
||||
* {@code Filter.orderedPermutations(list, Ordering.natural())}.
|
||||
*
|
||||
* @param elements the original iterable whose elements have to be permuted.
|
||||
* @return an immutable {@link Collection} containing all the different
|
||||
* permutations of the original iterable.
|
||||
* @throws NullPointerException if the specified iterable is null or has any
|
||||
* null elements.
|
||||
* @since 12.0
|
||||
*/
|
||||
// @Beta public static <E extends Comparable<? super E>>
|
||||
// Collection<List<E>> orderedPermutations(Iterable<E> elements) {
|
||||
// return orderedPermutations(elements, Ordering.natural());
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns a {@link Collection} of all the permutations of the specified
|
||||
* {@link Iterable} using the specified {@link Comparator} for establishing
|
||||
* the lexicographical ordering.
|
||||
*
|
||||
* <p>Examples: <pre> {@code
|
||||
*
|
||||
* for (List<String> perm : orderedPermutations(asList("b", "c", "a"))) {
|
||||
* println(perm);
|
||||
* }
|
||||
* // -> ["a", "b", "c"]
|
||||
* // -> ["a", "c", "b"]
|
||||
* // -> ["b", "a", "c"]
|
||||
* // -> ["b", "c", "a"]
|
||||
* // -> ["c", "a", "b"]
|
||||
* // -> ["c", "b", "a"]
|
||||
*
|
||||
* for (List<Integer> perm : orderedPermutations(asList(1, 2, 2, 1))) {
|
||||
* println(perm);
|
||||
* }
|
||||
* // -> [1, 1, 2, 2]
|
||||
* // -> [1, 2, 1, 2]
|
||||
* // -> [1, 2, 2, 1]
|
||||
* // -> [2, 1, 1, 2]
|
||||
* // -> [2, 1, 2, 1]
|
||||
* // -> [2, 2, 1, 1]}</pre>
|
||||
*
|
||||
* <p><i>Notes:</i> This is an implementation of the algorithm for
|
||||
* Lexicographical Permutations Generation, described in Knuth's "The Art of
|
||||
* Computer Programming", Volume 4, Chapter 7, Section 7.2.1.2. The
|
||||
* iteration order follows the lexicographical order. This means that
|
||||
* the first permutation will be in ascending order, and the last will be in
|
||||
* descending order.
|
||||
*
|
||||
* <p>Elements that compare equal are considered equal and no new permutations
|
||||
* are created by swapping them.
|
||||
*
|
||||
* <p>An empty iterable has only one permutation, which is an empty list.
|
||||
*
|
||||
* @param elements the original iterable whose elements have to be permuted.
|
||||
* @param comparator a comparator for the iterable's elements.
|
||||
* @return an immutable {@link Collection} containing all the different
|
||||
* permutations of the original iterable.
|
||||
* @throws NullPointerException If the specified iterable is null, has any
|
||||
* null elements, or if the specified comparator is null.
|
||||
* @since 12.0
|
||||
*/
|
||||
// @Beta public static <E> Collection<List<E>> orderedPermutations(
|
||||
// Iterable<E> elements, Comparator<? super E> comparator) {
|
||||
// return new OrderedPermutationCollection<E>(elements, comparator);
|
||||
// }
|
||||
|
||||
// private static final class OrderedPermutationCollection<E>
|
||||
// extends AbstractCollection<List<E>> {
|
||||
// final ImmutableList<E> inputList;
|
||||
// final Comparator<? super E> comparator;
|
||||
// final int size;
|
||||
//
|
||||
// OrderedPermutationCollection(Iterable<E> input,
|
||||
// Comparator<? super E> comparator) {
|
||||
// this.inputList = Ordering.from(comparator).immutableSortedCopy(input);
|
||||
// this.comparator = comparator;
|
||||
// this.size = calculateSize(inputList, comparator);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * The number of permutations with repeated elements is calculated as
|
||||
// * follows:
|
||||
// * <ul>
|
||||
// * <li>For an empty list, it is 1 (base case).</li>
|
||||
// * <li>When r numbers are added to a list of n-r elements, the number of
|
||||
// * permutations is increased by a factor of (n choose r).</li>
|
||||
// * </ul>
|
||||
// */
|
||||
// private static <E> int calculateSize(
|
||||
// List<E> sortedInputList, Comparator<? super E> comparator) {
|
||||
// long permutations = 1;
|
||||
// int n = 1;
|
||||
// int r = 1;
|
||||
// while (n < sortedInputList.size()) {
|
||||
// int comparison = comparator.compare(
|
||||
// sortedInputList.get(n - 1), sortedInputList.get(n));
|
||||
// if (comparison < 0) {
|
||||
// // We move to the next non-repeated element.
|
||||
// permutations *= binomial(n, r);
|
||||
// r = 0;
|
||||
// if (!isPositiveInt(permutations)) {
|
||||
// return Integer.MAX_VALUE;
|
||||
// }
|
||||
// }
|
||||
// n++;
|
||||
// r++;
|
||||
// }
|
||||
// permutations *= binomial(n, r);
|
||||
// if (!isPositiveInt(permutations)) {
|
||||
// return Integer.MAX_VALUE;
|
||||
// }
|
||||
// return (int) permutations;
|
||||
// }
|
||||
//
|
||||
// @Override public int size() {
|
||||
// return size;
|
||||
// }
|
||||
//
|
||||
// @Override public boolean isEmpty() {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// @Override public Iterator<List<E>> iterator() {
|
||||
// return new OrderedPermutationIterator<E>(inputList, comparator);
|
||||
// }
|
||||
//
|
||||
// @Override public boolean contains(Object obj) {
|
||||
// if (obj instanceof List) {
|
||||
// List<?> list = (List<?>) obj;
|
||||
// return isPermutation(inputList, list);
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// @Override public String toString() {
|
||||
// return "orderedPermutationCollection(" + inputList + ")";
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private static final class OrderedPermutationIterator<E>
|
||||
// extends AbstractIterator<List<E>> {
|
||||
//
|
||||
// List<E> nextPermutation;
|
||||
// final Comparator<? super E> comparator;
|
||||
//
|
||||
// OrderedPermutationIterator(List<E> list,
|
||||
// Comparator<? super E> comparator) {
|
||||
// this.nextPermutation = Lists.newArrayList(list);
|
||||
// this.comparator = comparator;
|
||||
// }
|
||||
//
|
||||
// @Override protected List<E> computeNext() {
|
||||
// if (nextPermutation == null) {
|
||||
// return endOfData();
|
||||
// }
|
||||
// ImmutableList<E> next = ImmutableList.copyOf(nextPermutation);
|
||||
// calculateNextPermutation();
|
||||
// return next;
|
||||
// }
|
||||
//
|
||||
// void calculateNextPermutation() {
|
||||
// int j = findNextJ();
|
||||
// if (j == -1) {
|
||||
// nextPermutation = null;
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// int l = findNextL(j);
|
||||
// Collections.swap(nextPermutation, j, l);
|
||||
// int n = nextPermutation.size();
|
||||
// Collections.reverse(nextPermutation.subList(j + 1, n));
|
||||
// }
|
||||
//
|
||||
// int findNextJ() {
|
||||
// for (int k = nextPermutation.size() - 2; k >= 0; k--) {
|
||||
// if (comparator.compare(nextPermutation.get(k),
|
||||
// nextPermutation.get(k + 1)) < 0) {
|
||||
// return k;
|
||||
// }
|
||||
// }
|
||||
// return -1;
|
||||
// }
|
||||
//
|
||||
// int findNextL(int j) {
|
||||
// E ak = nextPermutation.get(j);
|
||||
// for (int l = nextPermutation.size() - 1; l > j; l--) {
|
||||
// if (comparator.compare(ak, nextPermutation.get(l)) < 0) {
|
||||
// return l;
|
||||
// }
|
||||
// }
|
||||
// throw new AssertionError("this statement should be unreachable");
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns a {@link Collection} of all the permutations of the specified
|
||||
* {@link Collection}.
|
||||
*
|
||||
* <p><i>Notes:</i> This is an implementation of the Plain Changes algorithm
|
||||
* for permutations generation, described in Knuth's "The Art of Computer
|
||||
* Programming", Volume 4, Chapter 7, Section 7.2.1.2.
|
||||
*
|
||||
* <p>If the input list contains equal elements, some of the generated
|
||||
* permutations will be equal.
|
||||
*
|
||||
* <p>An empty collection has only one permutation, which is an empty list.
|
||||
*
|
||||
* @param elements the original collection whose elements have to be permuted.
|
||||
* @return an immutable {@link Collection} containing all the different
|
||||
* permutations of the original collection.
|
||||
* @throws NullPointerException if the specified collection is null or has any
|
||||
* null elements.
|
||||
* @since 12.0
|
||||
*/
|
||||
// @Beta public static <E> Collection<List<E>> permutations(
|
||||
// Collection<E> elements) {
|
||||
// return new PermutationCollection<E>(ImmutableList.copyOf(elements));
|
||||
// }
|
||||
//
|
||||
// private static final class PermutationCollection<E>
|
||||
// extends AbstractCollection<List<E>> {
|
||||
// final ImmutableList<E> inputList;
|
||||
//
|
||||
// PermutationCollection(ImmutableList<E> input) {
|
||||
// this.inputList = input;
|
||||
// }
|
||||
//
|
||||
// @Override public int size() {
|
||||
// return IntMath.factorial(inputList.size());
|
||||
// }
|
||||
//
|
||||
// @Override public boolean isEmpty() {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// @Override public Iterator<List<E>> iterator() {
|
||||
// return new PermutationIterator<E>(inputList);
|
||||
// }
|
||||
//
|
||||
// @Override public boolean contains(Object obj) {
|
||||
// if (obj instanceof List) {
|
||||
// List<?> list = (List<?>) obj;
|
||||
// return isPermutation(inputList, list);
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// @Override public String toString() {
|
||||
// return "permutations(" + inputList + ")";
|
||||
// }
|
||||
// }
|
||||
|
||||
// private static class PermutationIterator<E>
|
||||
// extends AbstractIterator<List<E>> {
|
||||
// final List<E> list;
|
||||
// final int[] c;
|
||||
// final int[] o;
|
||||
// int j;
|
||||
//
|
||||
// PermutationIterator(List<E> list) {
|
||||
// this.list = new ArrayList<E>(list);
|
||||
// int n = list.size();
|
||||
// c = new int[n];
|
||||
// o = new int[n];
|
||||
// Arrays.fill(c, 0);
|
||||
// Arrays.fill(o, 1);
|
||||
// j = Integer.MAX_VALUE;
|
||||
// }
|
||||
//
|
||||
// @Override protected List<E> computeNext() {
|
||||
// if (j <= 0) {
|
||||
// return endOfData();
|
||||
// }
|
||||
// ImmutableList<E> next = ImmutableList.copyOf(list);
|
||||
// calculateNextPermutation();
|
||||
// return next;
|
||||
// }
|
||||
//
|
||||
// void calculateNextPermutation() {
|
||||
// j = list.size() - 1;
|
||||
// int s = 0;
|
||||
//
|
||||
// // Handle the special case of an empty list. Skip the calculation of the
|
||||
// // next permutation.
|
||||
// if (j == -1) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// while (true) {
|
||||
// int q = c[j] + o[j];
|
||||
// if (q < 0) {
|
||||
// switchDirection();
|
||||
// continue;
|
||||
// }
|
||||
// if (q == j + 1) {
|
||||
// if (j == 0) {
|
||||
// break;
|
||||
// }
|
||||
// s++;
|
||||
// switchDirection();
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// Collections.swap(list, j - c[j] + s, j - q + s);
|
||||
// c[j] = q;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// void switchDirection() {
|
||||
// o[j] = -o[j];
|
||||
// j--;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Returns {@code true} if the second list is a permutation of the first.
|
||||
// */
|
||||
// private static boolean isPermutation(List<?> first,
|
||||
// List<?> second) {
|
||||
// if (first.size() != second.size()) {
|
||||
// return false;
|
||||
// }
|
||||
// Multiset<?> firstMultiset = HashMultiset.create(first);
|
||||
// Multiset<?> secondMultiset = HashMultiset.create(second);
|
||||
// return firstMultiset.equals(secondMultiset);
|
||||
// }
|
||||
|
||||
// private static boolean isPositiveInt(long n) {
|
||||
// return n >= 0 && n <= Integer.MAX_VALUE;
|
||||
// }
|
||||
}
|
250
java/src/game/collect/ForwardingCollection.java
Normal file
250
java/src/game/collect/ForwardingCollection.java
Normal file
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* A collection which forwards all its method calls to another collection.
|
||||
* Subclasses should override one or more methods to modify the behavior of the
|
||||
* backing collection as desired per the <a
|
||||
* href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
|
||||
*
|
||||
* <p><b>Warning:</b> The methods of {@code ForwardingCollection} forward
|
||||
* <b>indiscriminately</b> to the methods of the delegate. For example,
|
||||
* overriding {@link #add} alone <b>will not</b> change the behavior of {@link
|
||||
* #addAll}, which can lead to unexpected behavior. In this case, you should
|
||||
* override {@code addAll} as well, either providing your own implementation, or
|
||||
* delegating to the provided {@code standardAddAll} method.
|
||||
*
|
||||
* <p>The {@code standard} methods are not guaranteed to be thread-safe, even
|
||||
* when all of the methods that they depend on are thread-safe.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @author Louis Wasserman
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
|
||||
abstract class ForwardingCollection<E> extends ForwardingObject
|
||||
implements Collection<E> {
|
||||
// TODO(user): identify places where thread safety is actually lost
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingCollection() {}
|
||||
|
||||
@Override protected abstract Collection<E> delegate();
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return delegate().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return delegate().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> collection) {
|
||||
return delegate().removeAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return delegate().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object object) {
|
||||
return delegate().contains(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E element) {
|
||||
return delegate().add(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object object) {
|
||||
return delegate().remove(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> collection) {
|
||||
return delegate().containsAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> collection) {
|
||||
return delegate().addAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> collection) {
|
||||
return delegate().retainAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
delegate().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return delegate().toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] array) {
|
||||
return delegate().toArray(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #contains} in terms of {@link #iterator}.
|
||||
* If you override {@link #iterator}, you may wish to override {@link
|
||||
* #contains} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardContains(Object object) {
|
||||
return Iterators.contains(iterator(), object);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #containsAll} in terms of {@link #contains}
|
||||
* . If you override {@link #contains}, you may wish to override {@link
|
||||
* #containsAll} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardContainsAll(Collection<?> collection) {
|
||||
return Filter.containsAllImpl(this, collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #addAll} in terms of {@link #add}. If you
|
||||
* override {@link #add}, you may wish to override {@link #addAll} to forward
|
||||
* to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardAddAll(Collection<? extends E> collection) {
|
||||
return Iterators.addAll(this, collection.iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #remove} in terms of {@link #iterator},
|
||||
* using the iterator's {@code remove} method. If you override {@link
|
||||
* #iterator}, you may wish to override {@link #remove} to forward to this
|
||||
* implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardRemove(Object object) {
|
||||
Iterator<E> iterator = iterator();
|
||||
while (iterator.hasNext()) {
|
||||
if (Preconditions.equal(iterator.next(), object)) {
|
||||
iterator.remove();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #removeAll} in terms of {@link #iterator},
|
||||
* using the iterator's {@code remove} method. If you override {@link
|
||||
* #iterator}, you may wish to override {@link #removeAll} to forward to this
|
||||
* implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardRemoveAll(Collection<?> collection) {
|
||||
return Iterators.removeAll(iterator(), collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #retainAll} in terms of {@link #iterator},
|
||||
* using the iterator's {@code remove} method. If you override {@link
|
||||
* #iterator}, you may wish to override {@link #retainAll} to forward to this
|
||||
* implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardRetainAll(Collection<?> collection) {
|
||||
return Iterators.retainAll(iterator(), collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #clear} in terms of {@link #iterator},
|
||||
* using the iterator's {@code remove} method. If you override {@link
|
||||
* #iterator}, you may wish to override {@link #clear} to forward to this
|
||||
* implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected void standardClear() {
|
||||
Iterators.clear(iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #isEmpty} as {@code !iterator().hasNext}.
|
||||
* If you override {@link #isEmpty}, you may wish to override {@link #isEmpty}
|
||||
* to forward to this implementation. Alternately, it may be more efficient to
|
||||
* implement {@code isEmpty} as {@code size() == 0}.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardIsEmpty() {
|
||||
return !iterator().hasNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #toString} in terms of {@link #iterator}.
|
||||
* If you override {@link #iterator}, you may wish to override {@link
|
||||
* #toString} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
// protected String standardToString() {
|
||||
// return Filter.toStringImpl(this);
|
||||
// }
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #toArray()} in terms of {@link
|
||||
* #toArray(Object[])}. If you override {@link #toArray(Object[])}, you may
|
||||
* wish to override {@link #toArray} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected Object[] standardToArray() {
|
||||
Object[] newArray = new Object[size()];
|
||||
return toArray(newArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #toArray(Object[])} in terms of {@link
|
||||
* #size} and {@link #iterator}. If you override either of these methods, you
|
||||
* may wish to override {@link #toArray} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected <T> T[] standardToArray(T[] array) {
|
||||
return ObjectArrays.toArrayImpl(this, array);
|
||||
}
|
||||
}
|
302
java/src/game/collect/ForwardingMap.java
Normal file
302
java/src/game/collect/ForwardingMap.java
Normal file
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A map which forwards all its method calls to another map. Subclasses should
|
||||
* override one or more methods to modify the behavior of the backing map as
|
||||
* desired per the <a
|
||||
* href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
|
||||
*
|
||||
* <p><i>Warning:</i> The methods of {@code ForwardingMap} forward
|
||||
* <i>indiscriminately</i> to the methods of the delegate. For example,
|
||||
* overriding {@link #put} alone <i>will not</i> change the behavior of {@link
|
||||
* #putAll}, which can lead to unexpected behavior. In this case, you should
|
||||
* override {@code putAll} as well, either providing your own implementation, or
|
||||
* delegating to the provided {@code standardPutAll} method.
|
||||
*
|
||||
* <p>Each of the {@code standard} methods, where appropriate, use {@link
|
||||
* Objects#equal} to test equality for both keys and values. This may not be
|
||||
* the desired behavior for map implementations that use non-standard notions of
|
||||
* key equality, such as a {@code SortedMap} whose comparator is not consistent
|
||||
* with {@code equals}.
|
||||
*
|
||||
* <p>The {@code standard} methods and the collection views they return are not
|
||||
* guaranteed to be thread-safe, even when all of the methods that they depend
|
||||
* on are thread-safe.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @author Jared Levy
|
||||
* @author Louis Wasserman
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
|
||||
abstract class ForwardingMap<K, V> extends ForwardingObject
|
||||
implements Map<K, V> {
|
||||
// TODO(user): identify places where thread safety is actually lost
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingMap() {}
|
||||
|
||||
@Override protected abstract Map<K, V> delegate();
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return delegate().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return delegate().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object object) {
|
||||
return delegate().remove(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
delegate().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return delegate().containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return delegate().containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
return delegate().get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
return delegate().put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> map) {
|
||||
delegate().putAll(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return delegate().keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return delegate().values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return delegate().entrySet();
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object object) {
|
||||
return object == this || delegate().equals(object);
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
return delegate().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #putAll(Map)} in terms of {@link
|
||||
* #put(Object, Object)}. If you override {@link #put(Object, Object)}, you
|
||||
* may wish to override {@link #putAll(Map)} to forward to this
|
||||
* implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
// protected void standardPutAll(Map<? extends K, ? extends V> map) {
|
||||
// Maps.putAllImpl(this, map);
|
||||
// }
|
||||
|
||||
/**
|
||||
* A sensible, albeit inefficient, definition of {@link #remove} in terms of
|
||||
* the {@code iterator} method of {@link #entrySet}. If you override {@link
|
||||
* #entrySet}, you may wish to override {@link #remove} to forward to this
|
||||
* implementation.
|
||||
*
|
||||
* <p>Alternately, you may wish to override {@link #remove} with {@code
|
||||
* keySet().remove}, assuming that approach would not lead to an infinite
|
||||
* loop.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
// @Beta protected V standardRemove(Object key) {
|
||||
// Iterator<Entry<K, V>> entryIterator = entrySet().iterator();
|
||||
// while (entryIterator.hasNext()) {
|
||||
// Entry<K, V> entry = entryIterator.next();
|
||||
// if (Objects.equal(entry.getKey(), key)) {
|
||||
// V value = entry.getValue();
|
||||
// entryIterator.remove();
|
||||
// return value;
|
||||
// }
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #clear} in terms of the {@code iterator}
|
||||
* method of {@link #entrySet}. In many cases, you may wish to override
|
||||
* {@link #clear} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
// protected void standardClear() {
|
||||
// Iterators.clear(entrySet().iterator());
|
||||
// }
|
||||
|
||||
/**
|
||||
* A sensible implementation of {@link Map#keySet} in terms of the following
|
||||
* methods: {@link ForwardingMap#clear}, {@link ForwardingMap#containsKey},
|
||||
* {@link ForwardingMap#isEmpty}, {@link ForwardingMap#remove}, {@link
|
||||
* ForwardingMap#size}, and the {@link Set#iterator} method of {@link
|
||||
* ForwardingMap#entrySet}. In many cases, you may wish to override {@link
|
||||
* ForwardingMap#keySet} to forward to this implementation or a subclass
|
||||
* thereof.
|
||||
*
|
||||
* @since 10.0
|
||||
*/
|
||||
// @Beta
|
||||
// protected class StandardKeySet extends Maps.KeySet<K, V> {
|
||||
// /** Constructor for use by subclasses. */
|
||||
// public StandardKeySet() {
|
||||
// super(ForwardingMap.this);
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* A sensible, albeit inefficient, definition of {@link #containsKey} in terms
|
||||
* of the {@code iterator} method of {@link #entrySet}. If you override {@link
|
||||
* #entrySet}, you may wish to override {@link #containsKey} to forward to
|
||||
* this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
// @Beta protected boolean standardContainsKey(Object key) {
|
||||
// return Maps.containsKeyImpl(this, key);
|
||||
// }
|
||||
|
||||
/**
|
||||
* A sensible implementation of {@link Map#values} in terms of the following
|
||||
* methods: {@link ForwardingMap#clear}, {@link ForwardingMap#containsValue},
|
||||
* {@link ForwardingMap#isEmpty}, {@link ForwardingMap#size}, and the {@link
|
||||
* Set#iterator} method of {@link ForwardingMap#entrySet}. In many cases, you
|
||||
* may wish to override {@link ForwardingMap#values} to forward to this
|
||||
* implementation or a subclass thereof.
|
||||
*
|
||||
* @since 10.0
|
||||
*/
|
||||
// @Beta
|
||||
// protected class StandardValues extends Maps.Values<K, V> {
|
||||
// /** Constructor for use by subclasses. */
|
||||
// public StandardValues() {
|
||||
// super(ForwardingMap.this);
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #containsValue} in terms of the {@code
|
||||
* iterator} method of {@link #entrySet}. If you override {@link #entrySet},
|
||||
* you may wish to override {@link #containsValue} to forward to this
|
||||
* implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
// protected boolean standardContainsValue(Object value) {
|
||||
// return Maps.containsValueImpl(this, value);
|
||||
// }
|
||||
|
||||
/**
|
||||
* A sensible implementation of {@link Map#entrySet} in terms of the following
|
||||
* methods: {@link ForwardingMap#clear}, {@link ForwardingMap#containsKey},
|
||||
* {@link ForwardingMap#get}, {@link ForwardingMap#isEmpty}, {@link
|
||||
* ForwardingMap#remove}, and {@link ForwardingMap#size}. In many cases, you
|
||||
* may wish to override {@link #entrySet} to forward to this implementation
|
||||
* or a subclass thereof.
|
||||
*
|
||||
* @since 10.0
|
||||
*/
|
||||
// @Beta
|
||||
// protected abstract class StandardEntrySet extends Maps.EntrySet<K, V> {
|
||||
// /** Constructor for use by subclasses. */
|
||||
// public StandardEntrySet() {}
|
||||
//
|
||||
// @Override
|
||||
// Map<K, V> map() {
|
||||
// return ForwardingMap.this;
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #isEmpty} in terms of the {@code iterator}
|
||||
* method of {@link #entrySet}. If you override {@link #entrySet}, you may
|
||||
* wish to override {@link #isEmpty} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
// protected boolean standardIsEmpty() {
|
||||
// return !entrySet().iterator().hasNext();
|
||||
// }
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #equals} in terms of the {@code equals}
|
||||
* method of {@link #entrySet}. If you override {@link #entrySet}, you may
|
||||
* wish to override {@link #equals} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
// protected boolean standardEquals(Object object) {
|
||||
// return Maps.equalsImpl(this, object);
|
||||
// }
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #hashCode} in terms of the {@code iterator}
|
||||
* method of {@link #entrySet}. If you override {@link #entrySet}, you may
|
||||
* wish to override {@link #hashCode} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
// protected int standardHashCode() {
|
||||
// return Sets.hashCodeImpl(entrySet());
|
||||
// }
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #toString} in terms of the {@code iterator}
|
||||
* method of {@link #entrySet}. If you override {@link #entrySet}, you may
|
||||
* wish to override {@link #toString} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
// protected String standardToString() {
|
||||
// return Maps.toStringImpl(this);
|
||||
// }
|
||||
}
|
122
java/src/game/collect/ForwardingMapEntry.java
Normal file
122
java/src/game/collect/ForwardingMapEntry.java
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* A map entry which forwards all its method calls to another map entry.
|
||||
* Subclasses should override one or more methods to modify the behavior of the
|
||||
* backing map entry as desired per the <a
|
||||
* href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
|
||||
*
|
||||
* <p><i>Warning:</i> The methods of {@code ForwardingMapEntry} forward
|
||||
* <i>indiscriminately</i> to the methods of the delegate. For example,
|
||||
* overriding {@link #getValue} alone <i>will not</i> change the behavior of
|
||||
* {@link #equals}, which can lead to unexpected behavior. In this case, you
|
||||
* should override {@code equals} as well, either providing your own
|
||||
* implementation, or delegating to the provided {@code standardEquals} method.
|
||||
*
|
||||
* <p>Each of the {@code standard} methods, where appropriate, use {@link
|
||||
* Objects#equal} to test equality for both keys and values. This may not be
|
||||
* the desired behavior for map implementations that use non-standard notions of
|
||||
* key equality, such as the entry of a {@code SortedMap} whose comparator is
|
||||
* not consistent with {@code equals}.
|
||||
*
|
||||
* <p>The {@code standard} methods are not guaranteed to be thread-safe, even
|
||||
* when all of the methods that they depend on are thread-safe.
|
||||
*
|
||||
* @author Mike Bostock
|
||||
* @author Louis Wasserman
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
|
||||
abstract class ForwardingMapEntry<K, V>
|
||||
extends ForwardingObject implements Map.Entry<K, V> {
|
||||
// TODO(user): identify places where thread safety is actually lost
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingMapEntry() {}
|
||||
|
||||
@Override protected abstract Map.Entry<K, V> delegate();
|
||||
|
||||
@Override
|
||||
public K getKey() {
|
||||
return delegate().getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
return delegate().getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V setValue(V value) {
|
||||
return delegate().setValue(value);
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object object) {
|
||||
return delegate().equals(object);
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
return delegate().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #equals(Object)} in terms of {@link
|
||||
* #getKey()} and {@link #getValue()}. If you override either of these
|
||||
* methods, you may wish to override {@link #equals(Object)} to forward to
|
||||
* this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardEquals(Object object) {
|
||||
if (object instanceof Entry) {
|
||||
Entry<?, ?> that = (Entry<?, ?>) object;
|
||||
return Preconditions.equal(this.getKey(), that.getKey())
|
||||
&& Preconditions.equal(this.getValue(), that.getValue());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #hashCode()} in terms of {@link #getKey()}
|
||||
* and {@link #getValue()}. If you override either of these methods, you may
|
||||
* wish to override {@link #hashCode()} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
// protected int standardHashCode() {
|
||||
// K k = getKey();
|
||||
// V v = getValue();
|
||||
// return ((k == null) ? 0 : k.hashCode()) ^ ((v == null) ? 0 : v.hashCode());
|
||||
// }
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #toString} in terms of {@link
|
||||
* #getKey} and {@link #getValue}. If you override either of these
|
||||
* methods, you may wish to override {@link #equals} to forward to this
|
||||
* implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
// @Beta protected String standardToString() {
|
||||
// return getKey() + "=" + getValue();
|
||||
// }
|
||||
}
|
72
java/src/game/collect/ForwardingObject.java
Normal file
72
java/src/game/collect/ForwardingObject.java
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
/**
|
||||
* An abstract base class for implementing the <a
|
||||
* href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
|
||||
* The {@link #delegate()} method must be overridden to return the instance
|
||||
* being decorated.
|
||||
*
|
||||
* <p>This class does <i>not</i> forward the {@code hashCode} and {@code equals}
|
||||
* methods through to the backing object, but relies on {@code Object}'s
|
||||
* implementation. This is necessary to preserve the symmetry of {@code equals}.
|
||||
* Custom definitions of equality are usually based on an interface, such as
|
||||
* {@code Set} or {@code List}, so that the implementation of {@code equals} can
|
||||
* cast the object being tested for equality to the custom interface. {@code
|
||||
* ForwardingObject} implements no such custom interfaces directly; they
|
||||
* are implemented only in subclasses. Therefore, forwarding {@code equals}
|
||||
* would break symmetry, as the forwarding object might consider itself equal to
|
||||
* the object being tested, but the reverse could not be true. This behavior is
|
||||
* consistent with the JDK's collection wrappers, such as
|
||||
* {@link java.util.Collections#unmodifiableCollection}. Use an
|
||||
* interface-specific subclass of {@code ForwardingObject}, such as {@link
|
||||
* ForwardingList}, to preserve equality behavior, or override {@code equals}
|
||||
* directly.
|
||||
*
|
||||
* <p>The {@code toString} method is forwarded to the delegate. Although this
|
||||
* class does not implement {@link Serializable}, a serializable subclass may be
|
||||
* created since this class has a parameter-less constructor.
|
||||
*
|
||||
* @author Mike Bostock
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
|
||||
abstract class ForwardingObject {
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingObject() {}
|
||||
|
||||
/**
|
||||
* Returns the backing delegate instance that methods are forwarded to.
|
||||
* Abstract subclasses generally override this method with an abstract method
|
||||
* that has a more specific return type, such as {@link
|
||||
* ForwardingSet#delegate}. Concrete subclasses override this method to supply
|
||||
* the instance being decorated.
|
||||
*/
|
||||
protected abstract Object delegate();
|
||||
|
||||
/**
|
||||
* Returns the string representation generated by the delegate's
|
||||
* {@code toString} method.
|
||||
*/
|
||||
@Override public String toString() {
|
||||
return delegate().toString();
|
||||
}
|
||||
|
||||
/* No equals or hashCode. See class comments for details. */
|
||||
}
|
96
java/src/game/collect/ForwardingSet.java
Normal file
96
java/src/game/collect/ForwardingSet.java
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A set which forwards all its method calls to another set. Subclasses should
|
||||
* override one or more methods to modify the behavior of the backing set as
|
||||
* desired per the <a
|
||||
* href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
|
||||
*
|
||||
* <p><b>Warning:</b> The methods of {@code ForwardingSet} forward
|
||||
* <b>indiscriminately</b> to the methods of the delegate. For example,
|
||||
* overriding {@link #add} alone <b>will not</b> change the behavior of {@link
|
||||
* #addAll}, which can lead to unexpected behavior. In this case, you should
|
||||
* override {@code addAll} as well, either providing your own implementation, or
|
||||
* delegating to the provided {@code standardAddAll} method.
|
||||
*
|
||||
* <p>The {@code standard} methods are not guaranteed to be thread-safe, even
|
||||
* when all of the methods that they depend on are thread-safe.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @author Louis Wasserman
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
|
||||
abstract class ForwardingSet<E> extends ForwardingCollection<E>
|
||||
implements Set<E> {
|
||||
// TODO(user): identify places where thread safety is actually lost
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingSet() {}
|
||||
|
||||
@Override protected abstract Set<E> delegate();
|
||||
|
||||
@Override public boolean equals(Object object) {
|
||||
return object == this || delegate().equals(object);
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
return delegate().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #removeAll} in terms of {@link #iterator}
|
||||
* and {@link #remove}. If you override {@code iterator} or {@code remove},
|
||||
* you may wish to override {@link #removeAll} to forward to this
|
||||
* implementation.
|
||||
*
|
||||
* @since 7.0 (this version overrides the {@code ForwardingCollection} version as of 12.0)
|
||||
*/
|
||||
@Override
|
||||
protected boolean standardRemoveAll(Collection<?> collection) {
|
||||
return Sets.removeAllImpl(this, checkNotNull(collection)); // for GWT
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #equals} in terms of {@link #size} and
|
||||
* {@link #containsAll}. If you override either of those methods, you may wish
|
||||
* to override {@link #equals} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardEquals(Object object) {
|
||||
return Sets.equalsImpl(this, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #hashCode} in terms of {@link #iterator}.
|
||||
* If you override {@link #iterator}, you may wish to override {@link #equals}
|
||||
* to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected int standardHashCode() {
|
||||
return Sets.hashCodeImpl(this);
|
||||
}
|
||||
}
|
658
java/src/game/collect/HashBiMap.java
Normal file
658
java/src/game/collect/HashBiMap.java
Normal file
|
@ -0,0 +1,658 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.CollectPreconditions.checkNonnegative;
|
||||
import static game.collect.CollectPreconditions.checkRemove;
|
||||
import static game.collect.Preconditions.checkArgument;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Arrays;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A {@link BiMap} backed by two hash tables. This implementation allows null keys and values. A
|
||||
* {@code HashBiMap} and its inverse are both serializable.
|
||||
*
|
||||
* <p>See the Guava User Guide article on <a href=
|
||||
* "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#BiMap"> {@code BiMap}
|
||||
* </a>.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
* @author Mike Bostock
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
|
||||
public final class HashBiMap<K, V> extends AbstractMap<K, V> implements BiMap<K, V>, Serializable {
|
||||
|
||||
/**
|
||||
* Returns a new, empty {@code HashBiMap} with the default initial capacity (16).
|
||||
*/
|
||||
public static <K, V> HashBiMap<K, V> create() {
|
||||
return create(16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new, empty bimap with the specified expected size.
|
||||
*
|
||||
* @param expectedSize the expected number of entries
|
||||
* @throws IllegalArgumentException if the specified expected size is negative
|
||||
*/
|
||||
public static <K, V> HashBiMap<K, V> create(int expectedSize) {
|
||||
return new HashBiMap<K, V>(expectedSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new bimap containing initial values from {@code map}. The bimap is created with an
|
||||
* initial capacity sufficient to hold the mappings in the specified map.
|
||||
*/
|
||||
public static <K, V> HashBiMap<K, V> create(Map<? extends K, ? extends V> map) {
|
||||
HashBiMap<K, V> bimap = create(map.size());
|
||||
bimap.putAll(map);
|
||||
return bimap;
|
||||
}
|
||||
|
||||
private static final class BiEntry<K, V> extends ImmutableEntry<K, V> {
|
||||
final int keyHash;
|
||||
final int valueHash;
|
||||
|
||||
|
||||
BiEntry<K, V> nextInKToVBucket;
|
||||
|
||||
|
||||
BiEntry<K, V> nextInVToKBucket;
|
||||
|
||||
BiEntry(K key, int keyHash, V value, int valueHash) {
|
||||
super(key, value);
|
||||
this.keyHash = keyHash;
|
||||
this.valueHash = valueHash;
|
||||
}
|
||||
}
|
||||
|
||||
private static final double LOAD_FACTOR = 1.0;
|
||||
|
||||
private transient BiEntry<K, V>[] hashTableKToV;
|
||||
private transient BiEntry<K, V>[] hashTableVToK;
|
||||
private transient int size;
|
||||
private transient int mask;
|
||||
private transient int modCount;
|
||||
|
||||
private HashBiMap(int expectedSize) {
|
||||
init(expectedSize);
|
||||
}
|
||||
|
||||
private void init(int expectedSize) {
|
||||
checkNonnegative(expectedSize, "expectedSize");
|
||||
int tableSize = Hashing.closedTableSize(expectedSize, LOAD_FACTOR);
|
||||
this.hashTableKToV = createTable(tableSize);
|
||||
this.hashTableVToK = createTable(tableSize);
|
||||
this.mask = tableSize - 1;
|
||||
this.modCount = 0;
|
||||
this.size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and removes {@code entry} from the bucket linked lists in both the
|
||||
* key-to-value direction and the value-to-key direction.
|
||||
*/
|
||||
private void delete(BiEntry<K, V> entry) {
|
||||
int keyBucket = entry.keyHash & mask;
|
||||
BiEntry<K, V> prevBucketEntry = null;
|
||||
for (BiEntry<K, V> bucketEntry = hashTableKToV[keyBucket]; true;
|
||||
bucketEntry = bucketEntry.nextInKToVBucket) {
|
||||
if (bucketEntry == entry) {
|
||||
if (prevBucketEntry == null) {
|
||||
hashTableKToV[keyBucket] = entry.nextInKToVBucket;
|
||||
} else {
|
||||
prevBucketEntry.nextInKToVBucket = entry.nextInKToVBucket;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prevBucketEntry = bucketEntry;
|
||||
}
|
||||
|
||||
int valueBucket = entry.valueHash & mask;
|
||||
prevBucketEntry = null;
|
||||
for (BiEntry<K, V> bucketEntry = hashTableVToK[valueBucket];;
|
||||
bucketEntry = bucketEntry.nextInVToKBucket) {
|
||||
if (bucketEntry == entry) {
|
||||
if (prevBucketEntry == null) {
|
||||
hashTableVToK[valueBucket] = entry.nextInVToKBucket;
|
||||
} else {
|
||||
prevBucketEntry.nextInVToKBucket = entry.nextInVToKBucket;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prevBucketEntry = bucketEntry;
|
||||
}
|
||||
|
||||
size--;
|
||||
modCount++;
|
||||
}
|
||||
|
||||
private void insert(BiEntry<K, V> entry) {
|
||||
int keyBucket = entry.keyHash & mask;
|
||||
entry.nextInKToVBucket = hashTableKToV[keyBucket];
|
||||
hashTableKToV[keyBucket] = entry;
|
||||
|
||||
int valueBucket = entry.valueHash & mask;
|
||||
entry.nextInVToKBucket = hashTableVToK[valueBucket];
|
||||
hashTableVToK[valueBucket] = entry;
|
||||
|
||||
size++;
|
||||
modCount++;
|
||||
}
|
||||
|
||||
private static int hash(Object o) {
|
||||
return Hashing.smear((o == null) ? 0 : o.hashCode());
|
||||
}
|
||||
|
||||
private BiEntry<K, V> seekByKey(Object key, int keyHash) {
|
||||
for (BiEntry<K, V> entry = hashTableKToV[keyHash & mask]; entry != null;
|
||||
entry = entry.nextInKToVBucket) {
|
||||
if (keyHash == entry.keyHash && Preconditions.equal(key, entry.key)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private BiEntry<K, V> seekByValue(Object value, int valueHash) {
|
||||
for (BiEntry<K, V> entry = hashTableVToK[valueHash & mask]; entry != null;
|
||||
entry = entry.nextInVToKBucket) {
|
||||
if (valueHash == entry.valueHash && Preconditions.equal(value, entry.value)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return seekByKey(key, hash(key)) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return seekByValue(value, hash(value)) != null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
BiEntry<K, V> entry = seekByKey(key, hash(key));
|
||||
return (entry == null) ? null : entry.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
return put(key, value, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V forcePut(K key, V value) {
|
||||
return put(key, value, true);
|
||||
}
|
||||
|
||||
private V put(K key, V value, boolean force) {
|
||||
int keyHash = hash(key);
|
||||
int valueHash = hash(value);
|
||||
|
||||
BiEntry<K, V> oldEntryForKey = seekByKey(key, keyHash);
|
||||
if (oldEntryForKey != null && valueHash == oldEntryForKey.valueHash
|
||||
&& Preconditions.equal(value, oldEntryForKey.value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
BiEntry<K, V> oldEntryForValue = seekByValue(value, valueHash);
|
||||
if (oldEntryForValue != null) {
|
||||
if (force) {
|
||||
delete(oldEntryForValue);
|
||||
} else {
|
||||
throw new IllegalArgumentException("value already present: " + value);
|
||||
}
|
||||
}
|
||||
|
||||
if (oldEntryForKey != null) {
|
||||
delete(oldEntryForKey);
|
||||
}
|
||||
BiEntry<K, V> newEntry = new BiEntry<K, V>(key, keyHash, value, valueHash);
|
||||
insert(newEntry);
|
||||
rehashIfNecessary();
|
||||
return (oldEntryForKey == null) ? null : oldEntryForKey.value;
|
||||
}
|
||||
|
||||
|
||||
private K putInverse(V value, K key, boolean force) {
|
||||
int valueHash = hash(value);
|
||||
int keyHash = hash(key);
|
||||
|
||||
BiEntry<K, V> oldEntryForValue = seekByValue(value, valueHash);
|
||||
if (oldEntryForValue != null && keyHash == oldEntryForValue.keyHash
|
||||
&& Preconditions.equal(key, oldEntryForValue.key)) {
|
||||
return key;
|
||||
}
|
||||
|
||||
BiEntry<K, V> oldEntryForKey = seekByKey(key, keyHash);
|
||||
if (oldEntryForKey != null) {
|
||||
if (force) {
|
||||
delete(oldEntryForKey);
|
||||
} else {
|
||||
throw new IllegalArgumentException("value already present: " + key);
|
||||
}
|
||||
}
|
||||
|
||||
if (oldEntryForValue != null) {
|
||||
delete(oldEntryForValue);
|
||||
}
|
||||
BiEntry<K, V> newEntry = new BiEntry<K, V>(key, keyHash, value, valueHash);
|
||||
insert(newEntry);
|
||||
rehashIfNecessary();
|
||||
return (oldEntryForValue == null) ? null : oldEntryForValue.key;
|
||||
}
|
||||
|
||||
private void rehashIfNecessary() {
|
||||
BiEntry<K, V>[] oldKToV = hashTableKToV;
|
||||
if (Hashing.needsResizing(size, oldKToV.length, LOAD_FACTOR)) {
|
||||
int newTableSize = oldKToV.length * 2;
|
||||
|
||||
this.hashTableKToV = createTable(newTableSize);
|
||||
this.hashTableVToK = createTable(newTableSize);
|
||||
this.mask = newTableSize - 1;
|
||||
this.size = 0;
|
||||
|
||||
for (int bucket = 0; bucket < oldKToV.length; bucket++) {
|
||||
BiEntry<K, V> entry = oldKToV[bucket];
|
||||
while (entry != null) {
|
||||
BiEntry<K, V> nextEntry = entry.nextInKToVBucket;
|
||||
insert(entry);
|
||||
entry = nextEntry;
|
||||
}
|
||||
}
|
||||
this.modCount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private BiEntry<K, V>[] createTable(int length) {
|
||||
return new BiEntry[length];
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
BiEntry<K, V> entry = seekByKey(key, hash(key));
|
||||
if (entry == null) {
|
||||
return null;
|
||||
} else {
|
||||
delete(entry);
|
||||
return entry.value;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
size = 0;
|
||||
Arrays.fill(hashTableKToV, null);
|
||||
Arrays.fill(hashTableVToK, null);
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
abstract class Itr<T> implements Iterator<T> {
|
||||
int nextBucket = 0;
|
||||
BiEntry<K, V> next = null;
|
||||
BiEntry<K, V> toRemove = null;
|
||||
int expectedModCount = modCount;
|
||||
|
||||
private void checkForConcurrentModification() {
|
||||
if (modCount != expectedModCount) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
checkForConcurrentModification();
|
||||
if (next != null) {
|
||||
return true;
|
||||
}
|
||||
while (nextBucket < hashTableKToV.length) {
|
||||
if (hashTableKToV[nextBucket] != null) {
|
||||
next = hashTableKToV[nextBucket++];
|
||||
return true;
|
||||
}
|
||||
nextBucket++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
checkForConcurrentModification();
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
BiEntry<K, V> entry = next;
|
||||
next = entry.nextInKToVBucket;
|
||||
toRemove = entry;
|
||||
return output(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
checkForConcurrentModification();
|
||||
checkRemove(toRemove != null);
|
||||
delete(toRemove);
|
||||
expectedModCount = modCount;
|
||||
toRemove = null;
|
||||
}
|
||||
|
||||
abstract T output(BiEntry<K, V> entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return new KeySet();
|
||||
}
|
||||
|
||||
private final class KeySet extends Maps.KeySet<K, V> {
|
||||
KeySet() {
|
||||
super(HashBiMap.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<K> iterator() {
|
||||
return new Itr<K>() {
|
||||
@Override
|
||||
K output(BiEntry<K, V> entry) {
|
||||
return entry.key;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
BiEntry<K, V> entry = seekByKey(o, hash(o));
|
||||
if (entry == null) {
|
||||
return false;
|
||||
} else {
|
||||
delete(entry);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<V> values() {
|
||||
return inverse().keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return new EntrySet();
|
||||
}
|
||||
|
||||
private final class EntrySet extends Maps.EntrySet<K, V> {
|
||||
@Override
|
||||
Map<K, V> map() {
|
||||
return HashBiMap.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<K, V>> iterator() {
|
||||
return new Itr<Entry<K, V>>() {
|
||||
@Override
|
||||
Entry<K, V> output(BiEntry<K, V> entry) {
|
||||
return new MapEntry(entry);
|
||||
}
|
||||
|
||||
class MapEntry extends AbstractMapEntry<K, V> {
|
||||
BiEntry<K, V> delegate;
|
||||
|
||||
MapEntry(BiEntry<K, V> entry) {
|
||||
this.delegate = entry;
|
||||
}
|
||||
|
||||
@Override public K getKey() {
|
||||
return delegate.key;
|
||||
}
|
||||
|
||||
@Override public V getValue() {
|
||||
return delegate.value;
|
||||
}
|
||||
|
||||
@Override public V setValue(V value) {
|
||||
V oldValue = delegate.value;
|
||||
int valueHash = hash(value);
|
||||
if (valueHash == delegate.valueHash && Preconditions.equal(value, oldValue)) {
|
||||
return value;
|
||||
}
|
||||
checkArgument(
|
||||
seekByValue(value, valueHash) == null, "value already present: %s", value);
|
||||
delete(delegate);
|
||||
BiEntry<K, V> newEntry =
|
||||
new BiEntry<K, V>(delegate.key, delegate.keyHash, value, valueHash);
|
||||
insert(newEntry);
|
||||
expectedModCount = modCount;
|
||||
if (toRemove == delegate) {
|
||||
toRemove = newEntry;
|
||||
}
|
||||
delegate = newEntry;
|
||||
return oldValue;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private transient BiMap<V, K> inverse;
|
||||
|
||||
@Override
|
||||
public BiMap<V, K> inverse() {
|
||||
return (inverse == null) ? inverse = new Inverse() : inverse;
|
||||
}
|
||||
|
||||
private final class Inverse extends AbstractMap<V, K> implements BiMap<V, K>, Serializable {
|
||||
BiMap<K, V> forward() {
|
||||
return HashBiMap.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
forward().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object value) {
|
||||
return forward().containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public K get(Object value) {
|
||||
BiEntry<K, V> entry = seekByValue(value, hash(value));
|
||||
return (entry == null) ? null : entry.key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K put(V value, K key) {
|
||||
return putInverse(value, key, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public K forcePut(V value, K key) {
|
||||
return putInverse(value, key, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public K remove(Object value) {
|
||||
BiEntry<K, V> entry = seekByValue(value, hash(value));
|
||||
if (entry == null) {
|
||||
return null;
|
||||
} else {
|
||||
delete(entry);
|
||||
return entry.key;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiMap<K, V> inverse() {
|
||||
return forward();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<V> keySet() {
|
||||
return new InverseKeySet();
|
||||
}
|
||||
|
||||
private final class InverseKeySet extends Maps.KeySet<V, K> {
|
||||
InverseKeySet() {
|
||||
super(Inverse.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
BiEntry<K, V> entry = seekByValue(o, hash(o));
|
||||
if (entry == null) {
|
||||
return false;
|
||||
} else {
|
||||
delete(entry);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
return new Itr<V>() {
|
||||
@Override V output(BiEntry<K, V> entry) {
|
||||
return entry.value;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> values() {
|
||||
return forward().keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<V, K>> entrySet() {
|
||||
return new Maps.EntrySet<V, K>() {
|
||||
|
||||
@Override
|
||||
Map<V, K> map() {
|
||||
return Inverse.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<V, K>> iterator() {
|
||||
return new Itr<Entry<V, K>>() {
|
||||
@Override
|
||||
Entry<V, K> output(BiEntry<K, V> entry) {
|
||||
return new InverseEntry(entry);
|
||||
}
|
||||
|
||||
class InverseEntry extends AbstractMapEntry<V, K> {
|
||||
BiEntry<K, V> delegate;
|
||||
|
||||
InverseEntry(BiEntry<K, V> entry) {
|
||||
this.delegate = entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getKey() {
|
||||
return delegate.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K getValue() {
|
||||
return delegate.key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K setValue(K key) {
|
||||
K oldKey = delegate.key;
|
||||
int keyHash = hash(key);
|
||||
if (keyHash == delegate.keyHash && Preconditions.equal(key, oldKey)) {
|
||||
return key;
|
||||
}
|
||||
checkArgument(seekByKey(key, keyHash) == null, "value already present: %s", key);
|
||||
delete(delegate);
|
||||
BiEntry<K, V> newEntry =
|
||||
new BiEntry<K, V>(key, keyHash, delegate.value, delegate.valueHash);
|
||||
insert(newEntry);
|
||||
expectedModCount = modCount;
|
||||
// This is safe because entries can only get bumped up to earlier in the iteration,
|
||||
// so they can't get revisited.
|
||||
return oldKey;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Object writeReplace() {
|
||||
return new InverseSerializedForm<K, V>(HashBiMap.this);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class InverseSerializedForm<K, V> implements Serializable {
|
||||
private final HashBiMap<K, V> bimap;
|
||||
|
||||
InverseSerializedForm(HashBiMap<K, V> bimap) {
|
||||
this.bimap = bimap;
|
||||
}
|
||||
|
||||
Object readResolve() {
|
||||
return bimap.inverse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @serialData the number of entries, first key, first value, second key, second value, and so on.
|
||||
*/
|
||||
//
|
||||
// private void writeObject(ObjectOutputStream stream) throws IOException {
|
||||
// stream.defaultWriteObject();
|
||||
// Serialization.writeMap(this, stream);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
|
||||
// stream.defaultReadObject();
|
||||
// int size = Serialization.readCount(stream);
|
||||
// init(size);
|
||||
// Serialization.populateMap(this, stream, size);
|
||||
// }
|
||||
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
67
java/src/game/collect/Hashing.java
Normal file
67
java/src/game/collect/Hashing.java
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
/**
|
||||
* Static methods for implementing hash-based collections.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @author Jesse Wilson
|
||||
* @author Austin Appleby
|
||||
*/
|
||||
|
||||
final class Hashing {
|
||||
private Hashing() {}
|
||||
|
||||
private static final int C1 = 0xcc9e2d51;
|
||||
private static final int C2 = 0x1b873593;
|
||||
|
||||
/*
|
||||
* This method was rewritten in Java from an intermediate step of the Murmur hash function in
|
||||
* http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp, which contained the
|
||||
* following header:
|
||||
*
|
||||
* MurmurHash3 was written by Austin Appleby, and is placed in the public domain. The author
|
||||
* hereby disclaims copyright to this source code.
|
||||
*/
|
||||
static int smear(int hashCode) {
|
||||
return C2 * Integer.rotateLeft(hashCode * C1, 15);
|
||||
}
|
||||
|
||||
static int smearedHash(Object o) {
|
||||
return smear((o == null) ? 0 : o.hashCode());
|
||||
}
|
||||
|
||||
private static int MAX_TABLE_SIZE = 1 << (Integer.SIZE - 2);
|
||||
|
||||
static int closedTableSize(int expectedEntries, double loadFactor) {
|
||||
// Get the recommended table size.
|
||||
// Round down to the nearest power of 2.
|
||||
expectedEntries = Math.max(expectedEntries, 2);
|
||||
int tableSize = Integer.highestOneBit(expectedEntries);
|
||||
// Check to make sure that we will not exceed the maximum load factor.
|
||||
if (expectedEntries > (int) (loadFactor * tableSize)) {
|
||||
tableSize <<= 1;
|
||||
return (tableSize > 0) ? tableSize : MAX_TABLE_SIZE;
|
||||
}
|
||||
return tableSize;
|
||||
}
|
||||
|
||||
static boolean needsResizing(int size, int tableSize, double loadFactor) {
|
||||
return size > loadFactor * tableSize && tableSize < MAX_TABLE_SIZE;
|
||||
}
|
||||
}
|
81
java/src/game/collect/ImmutableAsList.java
Normal file
81
java/src/game/collect/ImmutableAsList.java
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (C) 2009 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* List returned by {@link ImmutableCollection#asList} that delegates {@code contains} checks
|
||||
* to the backing collection.
|
||||
*
|
||||
* @author Jared Levy
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
|
||||
|
||||
abstract class ImmutableAsList<E> extends ImmutableList<E> {
|
||||
abstract ImmutableCollection<E> delegateCollection();
|
||||
|
||||
@Override public boolean contains(Object target) {
|
||||
// The collection's contains() is at least as fast as ImmutableList's
|
||||
// and is often faster.
|
||||
return delegateCollection().contains(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return delegateCollection().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return delegateCollection().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return delegateCollection().isPartialView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialized form that leads to the same performance as the original list.
|
||||
*/
|
||||
|
||||
static class SerializedForm implements Serializable {
|
||||
final ImmutableCollection<?> collection;
|
||||
SerializedForm(ImmutableCollection<?> collection) {
|
||||
this.collection = collection;
|
||||
}
|
||||
Object readResolve() {
|
||||
return collection.asList();
|
||||
}
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws InvalidObjectException {
|
||||
throw new InvalidObjectException("Use SerializedForm");
|
||||
}
|
||||
|
||||
|
||||
@Override Object writeReplace() {
|
||||
return new SerializedForm(delegateCollection());
|
||||
}
|
||||
}
|
360
java/src/game/collect/ImmutableCollection.java
Normal file
360
java/src/game/collect/ImmutableCollection.java
Normal file
|
@ -0,0 +1,360 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.CollectPreconditions.checkNonnegative;
|
||||
import static game.collect.ObjectArrays.checkElementsNotNull;
|
||||
import static game.collect.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* An immutable collection. Does not permit null elements.
|
||||
*
|
||||
* <p>In addition to the {@link Collection} methods, this class has an {@link
|
||||
* #asList()} method, which returns a list view of the collection's elements.
|
||||
*
|
||||
* <p><b>Note:</b> Although this class is not final, it cannot be subclassed
|
||||
* outside of this package as it has no public or protected constructors. Thus,
|
||||
* instances of this type are guaranteed to be immutable.
|
||||
*
|
||||
* @author Jesse Wilson
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
|
||||
// we're overriding default serialization
|
||||
abstract class ImmutableCollection<E> extends AbstractCollection<E>
|
||||
implements Serializable {
|
||||
|
||||
ImmutableCollection() {}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable iterator across the elements in this collection.
|
||||
*/
|
||||
@Override
|
||||
public abstract UnmodifiableIterator<E> iterator();
|
||||
|
||||
@Override
|
||||
public final Object[] toArray() {
|
||||
int size = size();
|
||||
if (size == 0) {
|
||||
return ObjectArrays.EMPTY_ARRAY;
|
||||
}
|
||||
Object[] result = new Object[size()];
|
||||
copyIntoArray(result, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T[] toArray(T[] other) {
|
||||
checkNotNull(other);
|
||||
int size = size();
|
||||
if (other.length < size) {
|
||||
other = ObjectArrays.newArray(other, size);
|
||||
} else if (other.length > size) {
|
||||
other[size] = null;
|
||||
}
|
||||
copyIntoArray(other, 0);
|
||||
return other;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object object) {
|
||||
return object != null && super.contains(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the collection unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final boolean add(E e) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the collection unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final boolean remove(Object object) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the collection unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final boolean addAll(Collection<? extends E> newElements) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the collection unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final boolean removeAll(Collection<?> oldElements) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the collection unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final boolean retainAll(Collection<?> elementsToKeep) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the collection unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO(kevinb): Restructure code so ImmutableList doesn't contain this
|
||||
* variable, which it doesn't use.
|
||||
*/
|
||||
private transient ImmutableList<E> asList;
|
||||
|
||||
/**
|
||||
* Returns a list view of the collection.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public ImmutableList<E> asList() {
|
||||
ImmutableList<E> list = asList;
|
||||
return (list == null) ? (asList = createAsList()) : list;
|
||||
}
|
||||
|
||||
ImmutableList<E> createAsList() {
|
||||
switch (size()) {
|
||||
case 0:
|
||||
return ImmutableList.of();
|
||||
// case 1:
|
||||
// return ImmutableList.of(iterator().next());
|
||||
default:
|
||||
return new RegularImmutableAsList<E>(this, toArray());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this immutable collection's implementation contains references to
|
||||
* user-created objects that aren't accessible via this collection's methods. This is generally
|
||||
* used to determine whether {@code copyOf} implementations should make an explicit copy to avoid
|
||||
* memory leaks.
|
||||
*/
|
||||
abstract boolean isPartialView();
|
||||
|
||||
/**
|
||||
* Copies the contents of this immutable collection into the specified array at the specified
|
||||
* offset. Returns {@code offset + size()}.
|
||||
*/
|
||||
int copyIntoArray(Object[] dst, int offset) {
|
||||
for (E e : this) {
|
||||
dst[offset++] = e;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
Object writeReplace() {
|
||||
// We serialize by default to ImmutableList, the simplest thing that works.
|
||||
return new ImmutableList.SerializedForm(toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract base class for builders of {@link ImmutableCollection} types.
|
||||
*
|
||||
* @since 10.0
|
||||
*/
|
||||
public abstract static class Builder<E> {
|
||||
static final int DEFAULT_INITIAL_CAPACITY = 4;
|
||||
|
||||
static int expandedCapacity(int oldCapacity, int minCapacity) {
|
||||
if (minCapacity < 0) {
|
||||
throw new AssertionError("cannot store more than MAX_VALUE elements");
|
||||
}
|
||||
// careful of overflow!
|
||||
int newCapacity = oldCapacity + (oldCapacity >> 1) + 1;
|
||||
if (newCapacity < minCapacity) {
|
||||
newCapacity = Integer.highestOneBit(minCapacity - 1) << 1;
|
||||
}
|
||||
if (newCapacity < 0) {
|
||||
newCapacity = Integer.MAX_VALUE;
|
||||
// guaranteed to be >= newCapacity
|
||||
}
|
||||
return newCapacity;
|
||||
}
|
||||
|
||||
Builder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds {@code element} to the {@code ImmutableCollection} being built.
|
||||
*
|
||||
* <p>Note that each builder class covariantly returns its own type from
|
||||
* this method.
|
||||
*
|
||||
* @param element the element to add
|
||||
* @return this {@code Builder} instance
|
||||
* @throws NullPointerException if {@code element} is null
|
||||
*/
|
||||
public abstract Builder<E> add(E element);
|
||||
|
||||
/**
|
||||
* Adds each element of {@code elements} to the {@code ImmutableCollection}
|
||||
* being built.
|
||||
*
|
||||
* <p>Note that each builder class overrides this method in order to
|
||||
* covariantly return its own type.
|
||||
*
|
||||
* @param elements the elements to add
|
||||
* @return this {@code Builder} instance
|
||||
* @throws NullPointerException if {@code elements} is null or contains a
|
||||
* null element
|
||||
*/
|
||||
public Builder<E> add(E... elements) {
|
||||
for (E element : elements) {
|
||||
add(element);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds each element of {@code elements} to the {@code ImmutableCollection}
|
||||
* being built.
|
||||
*
|
||||
* <p>Note that each builder class overrides this method in order to
|
||||
* covariantly return its own type.
|
||||
*
|
||||
* @param elements the elements to add
|
||||
* @return this {@code Builder} instance
|
||||
* @throws NullPointerException if {@code elements} is null or contains a
|
||||
* null element
|
||||
*/
|
||||
public Builder<E> addAll(Iterable<? extends E> elements) {
|
||||
for (E element : elements) {
|
||||
add(element);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds each element of {@code elements} to the {@code ImmutableCollection}
|
||||
* being built.
|
||||
*
|
||||
* <p>Note that each builder class overrides this method in order to
|
||||
* covariantly return its own type.
|
||||
*
|
||||
* @param elements the elements to add
|
||||
* @return this {@code Builder} instance
|
||||
* @throws NullPointerException if {@code elements} is null or contains a
|
||||
* null element
|
||||
*/
|
||||
public Builder<E> addAll(Iterator<? extends E> elements) {
|
||||
while (elements.hasNext()) {
|
||||
add(elements.next());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a newly-created {@code ImmutableCollection} of the appropriate
|
||||
* type, containing the elements provided to this builder.
|
||||
*
|
||||
* <p>Note that each builder class covariantly returns the appropriate type
|
||||
* of {@code ImmutableCollection} from this method.
|
||||
*/
|
||||
public abstract ImmutableCollection<E> build();
|
||||
}
|
||||
|
||||
abstract static class ArrayBasedBuilder<E> extends ImmutableCollection.Builder<E> {
|
||||
Object[] contents;
|
||||
int size;
|
||||
|
||||
ArrayBasedBuilder(int initialCapacity) {
|
||||
checkNonnegative(initialCapacity, "initialCapacity");
|
||||
this.contents = new Object[initialCapacity];
|
||||
this.size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand the absolute capacity of the builder so it can accept at least
|
||||
* the specified number of elements without being resized.
|
||||
*/
|
||||
private void ensureCapacity(int minCapacity) {
|
||||
if (contents.length < minCapacity) {
|
||||
this.contents = ObjectArrays.arraysCopyOf(
|
||||
this.contents, expandedCapacity(contents.length, minCapacity));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayBasedBuilder<E> add(E element) {
|
||||
checkNotNull(element);
|
||||
ensureCapacity(size + 1);
|
||||
contents[size++] = element;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<E> add(E... elements) {
|
||||
checkElementsNotNull(elements);
|
||||
ensureCapacity(size + elements.length);
|
||||
System.arraycopy(elements, 0, contents, size, elements.length);
|
||||
size += elements.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<E> addAll(Iterable<? extends E> elements) {
|
||||
if (elements instanceof Collection) {
|
||||
Collection<?> collection = (Collection<?>) elements;
|
||||
ensureCapacity(size + collection.size());
|
||||
}
|
||||
super.addAll(elements);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
48
java/src/game/collect/ImmutableEntry.java
Normal file
48
java/src/game/collect/ImmutableEntry.java
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @see game.collect.Maps#immutableEntry(Object, Object)
|
||||
*/
|
||||
|
||||
class ImmutableEntry<K, V> extends AbstractMapEntry<K, V>
|
||||
implements Serializable {
|
||||
final K key;
|
||||
final V value;
|
||||
|
||||
ImmutableEntry(K key, V value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override public final K getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override public final V getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override public final V setValue(V value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
146
java/src/game/collect/ImmutableEnumMap.java
Normal file
146
java/src/game/collect/ImmutableEnumMap.java
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Copyright (C) 2012 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.Preconditions.checkArgument;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ImmutableMap} backed by a non-empty {@link
|
||||
* java.util.EnumMap}.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
|
||||
// we're overriding default serialization
|
||||
final class ImmutableEnumMap<K extends Enum<K>, V> extends ImmutableMap<K, V> {
|
||||
static <K extends Enum<K>, V> ImmutableMap<K, V> asImmutable(EnumMap<K, V> map) {
|
||||
switch (map.size()) {
|
||||
case 0:
|
||||
return ImmutableMap.of();
|
||||
// case 1: {
|
||||
// Entry<K, V> entry = Iterables.getOnlyElement(map.entrySet());
|
||||
// return ImmutableMap.of(entry.getKey(), entry.getValue());
|
||||
// }
|
||||
default:
|
||||
return new ImmutableEnumMap<K, V>(map);
|
||||
}
|
||||
}
|
||||
|
||||
private transient final EnumMap<K, V> delegate;
|
||||
|
||||
private ImmutableEnumMap(EnumMap<K, V> delegate) {
|
||||
this.delegate = delegate;
|
||||
checkArgument(!delegate.isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableSet<K> createKeySet() {
|
||||
return new ImmutableSet<K>() {
|
||||
|
||||
@Override
|
||||
public boolean contains(Object object) {
|
||||
return delegate.containsKey(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return ImmutableEnumMap.this.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnmodifiableIterator<K> iterator() {
|
||||
return Iterators.unmodifiableIterator(delegate.keySet().iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return delegate.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return delegate.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
return delegate.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableSet<Entry<K, V>> createEntrySet() {
|
||||
return new ImmutableMapEntrySet<K, V>() {
|
||||
|
||||
@Override
|
||||
ImmutableMap<K, V> map() {
|
||||
return ImmutableEnumMap.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnmodifiableIterator<Entry<K, V>> iterator() {
|
||||
return new UnmodifiableIterator<Entry<K, V>>() {
|
||||
private final Iterator<Entry<K, V>> backingIterator = delegate.entrySet().iterator();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return backingIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<K, V> next() {
|
||||
Entry<K, V> entry = backingIterator.next();
|
||||
return Maps.immutableEntry(entry.getKey(), entry.getValue());
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// All callers of the constructor are restricted to <K extends Enum<K>>.
|
||||
// @Override Object writeReplace() {
|
||||
// return new EnumSerializedForm<K, V>(delegate);
|
||||
// }
|
||||
//
|
||||
// /*
|
||||
// * This class is used to serialize ImmutableEnumSet instances.
|
||||
// */
|
||||
// private static class EnumSerializedForm<K extends Enum<K>, V>
|
||||
// implements Serializable {
|
||||
// final EnumMap<K, V> delegate;
|
||||
// EnumSerializedForm(EnumMap<K, V> delegate) {
|
||||
// this.delegate = delegate;
|
||||
// }
|
||||
// Object readResolve() {
|
||||
// return new ImmutableEnumMap<K, V>(delegate);
|
||||
// }
|
||||
// private static final long serialVersionUID = 0;
|
||||
// }
|
||||
}
|
117
java/src/game/collect/ImmutableEnumSet.java
Normal file
117
java/src/game/collect/ImmutableEnumSet.java
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (C) 2009 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ImmutableSet} backed by a non-empty {@link
|
||||
* java.util.EnumSet}.
|
||||
*
|
||||
* @author Jared Levy
|
||||
*/
|
||||
|
||||
// we're overriding default serialization
|
||||
final class ImmutableEnumSet<E extends Enum<E>> extends ImmutableSet<E> {
|
||||
static <E extends Enum<E>> ImmutableSet<E> asImmutable(EnumSet<E> set) {
|
||||
switch (set.size()) {
|
||||
case 0:
|
||||
return ImmutableSet.of();
|
||||
// case 1:
|
||||
// return ImmutableSet.of(Iterables.getOnlyElement(set));
|
||||
default:
|
||||
return new ImmutableEnumSet<E>(set);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Notes on EnumSet and <E extends Enum<E>>:
|
||||
*
|
||||
* This class isn't an arbitrary ForwardingImmutableSet because we need to
|
||||
* know that calling {@code clone()} during deserialization will return an
|
||||
* object that no one else has a reference to, allowing us to guarantee
|
||||
* immutability. Hence, we support only {@link EnumSet}.
|
||||
*/
|
||||
private final transient EnumSet<E> delegate;
|
||||
|
||||
private ImmutableEnumSet(EnumSet<E> delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override boolean isPartialView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public UnmodifiableIterator<E> iterator() {
|
||||
return Iterators.unmodifiableIterator(delegate.iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return delegate.size();
|
||||
}
|
||||
|
||||
@Override public boolean contains(Object object) {
|
||||
return delegate.contains(object);
|
||||
}
|
||||
|
||||
@Override public boolean containsAll(Collection<?> collection) {
|
||||
return delegate.containsAll(collection);
|
||||
}
|
||||
|
||||
@Override public boolean isEmpty() {
|
||||
return delegate.isEmpty();
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object object) {
|
||||
return object == this || delegate.equals(object);
|
||||
}
|
||||
|
||||
private transient int hashCode;
|
||||
|
||||
@Override public int hashCode() {
|
||||
int result = hashCode;
|
||||
return (result == 0) ? hashCode = delegate.hashCode() : result;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
|
||||
// All callers of the constructor are restricted to <E extends Enum<E>>.
|
||||
@Override Object writeReplace() {
|
||||
return new EnumSerializedForm<E>(delegate);
|
||||
}
|
||||
|
||||
/*
|
||||
* This class is used to serialize ImmutableEnumSet instances.
|
||||
*/
|
||||
private static class EnumSerializedForm<E extends Enum<E>>
|
||||
implements Serializable {
|
||||
final EnumSet<E> delegate;
|
||||
EnumSerializedForm(EnumSet<E> delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
Object readResolve() {
|
||||
// EJ2 #76: Write readObject() methods defensively.
|
||||
return new ImmutableEnumSet<E>(delegate.clone());
|
||||
}
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
}
|
743
java/src/game/collect/ImmutableList.java
Normal file
743
java/src/game/collect/ImmutableList.java
Normal file
|
@ -0,0 +1,743 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.ObjectArrays.arraysCopyOf;
|
||||
import static game.collect.ObjectArrays.checkElementsNotNull;
|
||||
import static game.collect.Preconditions.checkElementIndex;
|
||||
import static game.collect.Preconditions.checkNotNull;
|
||||
import static game.collect.Preconditions.checkPositionIndexes;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.RandomAccess;
|
||||
|
||||
/**
|
||||
* A high-performance, immutable, random-access {@code List} implementation.
|
||||
* Does not permit null elements.
|
||||
*
|
||||
* <p>Unlike {@link Collections#unmodifiableList}, which is a <i>view</i> of a
|
||||
* separate collection that can still change, an instance of {@code
|
||||
* ImmutableList} contains its own private data and will <i>never</i> change.
|
||||
* {@code ImmutableList} is convenient for {@code public static final} lists
|
||||
* ("constant lists") and also lets you easily make a "defensive copy" of a list
|
||||
* provided to your class by a caller.
|
||||
*
|
||||
* <p><b>Note:</b> Although this class is not final, it cannot be subclassed as
|
||||
* it has no public or protected constructors. Thus, instances of this type are
|
||||
* guaranteed to be immutable.
|
||||
*
|
||||
* <p>See the Guava User Guide article on <a href=
|
||||
* "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
|
||||
* immutable collections</a>.
|
||||
*
|
||||
* @see ImmutableMap
|
||||
* @see ImmutableSet
|
||||
* @author Kevin Bourrillion
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
|
||||
// we're overriding default serialization
|
||||
public abstract class ImmutableList<E> extends ImmutableCollection<E>
|
||||
implements List<E>, RandomAccess {
|
||||
|
||||
private static final ImmutableList<Object> EMPTY =
|
||||
new RegularImmutableList<Object>(ObjectArrays.EMPTY_ARRAY);
|
||||
|
||||
/**
|
||||
* Returns the empty immutable list. This set behaves and performs comparably
|
||||
* to {@link Collections#emptyList}, and is preferable mainly for consistency
|
||||
* and maintainability of your code.
|
||||
*/
|
||||
// Casting to any type is safe because the list will never hold any elements.
|
||||
|
||||
public static <E> ImmutableList<E> of() {
|
||||
return (ImmutableList<E>) EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing a single element. This list behaves
|
||||
* and performs comparably to {@link Collections#singleton}, but will not
|
||||
* accept a null element. It is preferable mainly for consistency and
|
||||
* maintainability of your code.
|
||||
*
|
||||
* @throws NullPointerException if {@code element} is null
|
||||
*/
|
||||
// public static <E> ImmutableList<E> of(E element) {
|
||||
// return new SingletonImmutableList<E>(element);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing the given elements, in order.
|
||||
*
|
||||
* @throws NullPointerException if any element is null
|
||||
*/
|
||||
public static <E> ImmutableList<E> of(E e1, E e2) {
|
||||
return construct(e1, e2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing the given elements, in order.
|
||||
*
|
||||
* @throws NullPointerException if any element is null
|
||||
*/
|
||||
public static <E> ImmutableList<E> of(E e1, E e2, E e3) {
|
||||
return construct(e1, e2, e3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing the given elements, in order.
|
||||
*
|
||||
* @throws NullPointerException if any element is null
|
||||
*/
|
||||
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4) {
|
||||
return construct(e1, e2, e3, e4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing the given elements, in order.
|
||||
*
|
||||
* @throws NullPointerException if any element is null
|
||||
*/
|
||||
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5) {
|
||||
return construct(e1, e2, e3, e4, e5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing the given elements, in order.
|
||||
*
|
||||
* @throws NullPointerException if any element is null
|
||||
*/
|
||||
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
|
||||
return construct(e1, e2, e3, e4, e5, e6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing the given elements, in order.
|
||||
*
|
||||
* @throws NullPointerException if any element is null
|
||||
*/
|
||||
public static <E> ImmutableList<E> of(
|
||||
E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
|
||||
return construct(e1, e2, e3, e4, e5, e6, e7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing the given elements, in order.
|
||||
*
|
||||
* @throws NullPointerException if any element is null
|
||||
*/
|
||||
public static <E> ImmutableList<E> of(
|
||||
E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
|
||||
return construct(e1, e2, e3, e4, e5, e6, e7, e8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing the given elements, in order.
|
||||
*
|
||||
* @throws NullPointerException if any element is null
|
||||
*/
|
||||
public static <E> ImmutableList<E> of(
|
||||
E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
|
||||
return construct(e1, e2, e3, e4, e5, e6, e7, e8, e9);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing the given elements, in order.
|
||||
*
|
||||
* @throws NullPointerException if any element is null
|
||||
*/
|
||||
public static <E> ImmutableList<E> of(
|
||||
E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
|
||||
return construct(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing the given elements, in order.
|
||||
*
|
||||
* @throws NullPointerException if any element is null
|
||||
*/
|
||||
public static <E> ImmutableList<E> of(
|
||||
E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10, E e11) {
|
||||
return construct(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11);
|
||||
}
|
||||
|
||||
// These go up to eleven. After that, you just get the varargs form, and
|
||||
// whatever warnings might come along with it. :(
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing the given elements, in order.
|
||||
*
|
||||
* @throws NullPointerException if any element is null
|
||||
* @since 3.0 (source-compatible since 2.0)
|
||||
*/
|
||||
public static <E> ImmutableList<E> of(
|
||||
E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10, E e11, E e12,
|
||||
E... others) {
|
||||
Object[] array = new Object[12 + others.length];
|
||||
array[0] = e1;
|
||||
array[1] = e2;
|
||||
array[2] = e3;
|
||||
array[3] = e4;
|
||||
array[4] = e5;
|
||||
array[5] = e6;
|
||||
array[6] = e7;
|
||||
array[7] = e8;
|
||||
array[8] = e9;
|
||||
array[9] = e10;
|
||||
array[10] = e11;
|
||||
array[11] = e12;
|
||||
System.arraycopy(others, 0, array, 12, others.length);
|
||||
return construct(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing the given elements, in order. If
|
||||
* {@code elements} is a {@link Collection}, this method behaves exactly as
|
||||
* {@link #copyOf(Collection)}; otherwise, it behaves exactly as {@code
|
||||
* copyOf(elements.iterator()}.
|
||||
*
|
||||
* @throws NullPointerException if any of {@code elements} is null
|
||||
*/
|
||||
public static <E> ImmutableList<E> copyOf(Iterable<? extends E> elements) {
|
||||
checkNotNull(elements); // TODO(kevinb): is this here only for GWT?
|
||||
return (elements instanceof Collection)
|
||||
? copyOf(Filter.cast(elements))
|
||||
: copyOf(elements.iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing the given elements, in order.
|
||||
*
|
||||
* <p>Despite the method name, this method attempts to avoid actually copying
|
||||
* the data when it is safe to do so. The exact circumstances under which a
|
||||
* copy will or will not be performed are undocumented and subject to change.
|
||||
*
|
||||
* <p>Note that if {@code list} is a {@code List<String>}, then {@code
|
||||
* ImmutableList.copyOf(list)} returns an {@code ImmutableList<String>}
|
||||
* containing each of the strings in {@code list}, while
|
||||
* ImmutableList.of(list)} returns an {@code ImmutableList<List<String>>}
|
||||
* containing one element (the given list itself).
|
||||
*
|
||||
* <p>This method is safe to use even when {@code elements} is a synchronized
|
||||
* or concurrent collection that is currently being modified by another
|
||||
* thread.
|
||||
*
|
||||
* @throws NullPointerException if any of {@code elements} is null
|
||||
*/
|
||||
public static <E> ImmutableList<E> copyOf(Collection<? extends E> elements) {
|
||||
if (elements instanceof ImmutableCollection) {
|
||||
// all supported methods are covariant
|
||||
ImmutableList<E> list = ((ImmutableCollection<E>) elements).asList();
|
||||
return list.isPartialView()
|
||||
? ImmutableList.<E>asImmutableList(list.toArray())
|
||||
: list;
|
||||
}
|
||||
return construct(elements.toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing the given elements, in order.
|
||||
*
|
||||
* @throws NullPointerException if any of {@code elements} is null
|
||||
*/
|
||||
public static <E> ImmutableList<E> copyOf(Iterator<? extends E> elements) {
|
||||
// We special-case for 0 or 1 elements, but going further is madness.
|
||||
if (!elements.hasNext()) {
|
||||
return of();
|
||||
}
|
||||
// E first = elements.next();
|
||||
// if (!elements.hasNext()) {
|
||||
// return of(first);
|
||||
// } else {
|
||||
return new ImmutableList.Builder<E>()
|
||||
// .add(first)
|
||||
.addAll(elements)
|
||||
.build();
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing the given elements, in order.
|
||||
*
|
||||
* @throws NullPointerException if any of {@code elements} is null
|
||||
* @since 3.0
|
||||
*/
|
||||
public static <E> ImmutableList<E> copyOf(E[] elements) {
|
||||
switch (elements.length) {
|
||||
case 0:
|
||||
return ImmutableList.of();
|
||||
// case 1:
|
||||
// return new SingletonImmutableList<E>(elements[0]);
|
||||
default:
|
||||
return new RegularImmutableList<E>(checkElementsNotNull(elements.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Views the array as an immutable list. Checks for nulls; does not copy.
|
||||
*/
|
||||
private static <E> ImmutableList<E> construct(Object... elements) {
|
||||
return asImmutableList(checkElementsNotNull(elements));
|
||||
}
|
||||
|
||||
/**
|
||||
* Views the array as an immutable list. Does not check for nulls; does not copy.
|
||||
*
|
||||
* <p>The array must be internally created.
|
||||
*/
|
||||
static <E> ImmutableList<E> asImmutableList(Object[] elements) {
|
||||
return asImmutableList(elements, elements.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Views the array as an immutable list. Copies if the specified range does not cover the complete
|
||||
* array. Does not check for nulls.
|
||||
*/
|
||||
static <E> ImmutableList<E> asImmutableList(Object[] elements, int length) {
|
||||
switch (length) {
|
||||
case 0:
|
||||
return of();
|
||||
// case 1:
|
||||
// // collection had only Es in it
|
||||
// ImmutableList<E> list = new SingletonImmutableList<E>((E) elements[0]);
|
||||
// return list;
|
||||
default:
|
||||
if (length < elements.length) {
|
||||
elements = arraysCopyOf(elements, length);
|
||||
}
|
||||
return new RegularImmutableList<E>(elements);
|
||||
}
|
||||
}
|
||||
|
||||
ImmutableList() {}
|
||||
|
||||
// This declaration is needed to make List.iterator() and
|
||||
// ImmutableCollection.iterator() consistent.
|
||||
@Override public UnmodifiableIterator<E> iterator() {
|
||||
return listIterator();
|
||||
}
|
||||
|
||||
@Override public UnmodifiableListIterator<E> listIterator() {
|
||||
return listIterator(0);
|
||||
}
|
||||
|
||||
@Override public UnmodifiableListIterator<E> listIterator(int index) {
|
||||
return new AbstractIndexedListIterator<E>(size(), index) {
|
||||
@Override
|
||||
protected E get(int index) {
|
||||
return ImmutableList.this.get(index);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object object) {
|
||||
return (object == null) ? -1 : indexOfImpl(this, object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf(Object object) {
|
||||
return (object == null) ? -1 : lastIndexOfImpl(this, object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object object) {
|
||||
return indexOf(object) >= 0;
|
||||
}
|
||||
|
||||
// constrain the return type to ImmutableList<E>
|
||||
|
||||
/**
|
||||
* Returns an immutable list of the elements between the specified {@code
|
||||
* fromIndex}, inclusive, and {@code toIndex}, exclusive. (If {@code
|
||||
* fromIndex} and {@code toIndex} are equal, the empty immutable list is
|
||||
* returned.)
|
||||
*/
|
||||
@Override
|
||||
public ImmutableList<E> subList(int fromIndex, int toIndex) {
|
||||
checkPositionIndexes(fromIndex, toIndex, size());
|
||||
int length = toIndex - fromIndex;
|
||||
switch (length) {
|
||||
case 0:
|
||||
return of();
|
||||
// case 1:
|
||||
// return of(get(fromIndex));
|
||||
default:
|
||||
return subListUnchecked(fromIndex, toIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the default implementation of {@link #subList} when {@code
|
||||
* toIndex - fromIndex > 1}, after index validation has already been
|
||||
* performed.
|
||||
*/
|
||||
ImmutableList<E> subListUnchecked(int fromIndex, int toIndex) {
|
||||
return new SubList(fromIndex, toIndex - fromIndex);
|
||||
}
|
||||
|
||||
class SubList extends ImmutableList<E> {
|
||||
transient final int offset;
|
||||
transient final int length;
|
||||
|
||||
SubList(int offset, int length) {
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int index) {
|
||||
checkElementIndex(index, length);
|
||||
return ImmutableList.this.get(index + offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<E> subList(int fromIndex, int toIndex) {
|
||||
checkPositionIndexes(fromIndex, toIndex, length);
|
||||
return ImmutableList.this.subList(fromIndex + offset, toIndex + offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the list unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final boolean addAll(int index, Collection<? extends E> newElements) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the list unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final E set(int index, E element) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the list unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final void add(int index, E element) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the list unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final E remove(int index) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this list instance.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
@Override public final ImmutableList<E> asList() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
int copyIntoArray(Object[] dst, int offset) {
|
||||
// this loop is faster for RandomAccess instances, which ImmutableLists are
|
||||
int size = size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
dst[offset + i] = get(i);
|
||||
}
|
||||
return offset + size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view of this immutable list in reverse order. For example, {@code
|
||||
* ImmutableList.of(1, 2, 3).reverse()} is equivalent to {@code
|
||||
* ImmutableList.of(3, 2, 1)}.
|
||||
*
|
||||
* @return a view of this immutable list in reverse order
|
||||
* @since 7.0
|
||||
*/
|
||||
public ImmutableList<E> reverse() {
|
||||
return new ReverseImmutableList<E>(this);
|
||||
}
|
||||
|
||||
private static class ReverseImmutableList<E> extends ImmutableList<E> {
|
||||
private final transient ImmutableList<E> forwardList;
|
||||
|
||||
ReverseImmutableList(ImmutableList<E> backingList) {
|
||||
this.forwardList = backingList;
|
||||
}
|
||||
|
||||
private int reverseIndex(int index) {
|
||||
return (size() - 1) - index;
|
||||
}
|
||||
|
||||
private int reversePosition(int index) {
|
||||
return size() - index;
|
||||
}
|
||||
|
||||
@Override public ImmutableList<E> reverse() {
|
||||
return forwardList;
|
||||
}
|
||||
|
||||
@Override public boolean contains(Object object) {
|
||||
return forwardList.contains(object);
|
||||
}
|
||||
|
||||
@Override public int indexOf(Object object) {
|
||||
int index = forwardList.lastIndexOf(object);
|
||||
return (index >= 0) ? reverseIndex(index) : -1;
|
||||
}
|
||||
|
||||
@Override public int lastIndexOf(Object object) {
|
||||
int index = forwardList.indexOf(object);
|
||||
return (index >= 0) ? reverseIndex(index) : -1;
|
||||
}
|
||||
|
||||
@Override public ImmutableList<E> subList(int fromIndex, int toIndex) {
|
||||
checkPositionIndexes(fromIndex, toIndex, size());
|
||||
return forwardList.subList(
|
||||
reversePosition(toIndex), reversePosition(fromIndex)).reverse();
|
||||
}
|
||||
|
||||
@Override public E get(int index) {
|
||||
checkElementIndex(index, size());
|
||||
return forwardList.get(reverseIndex(index));
|
||||
}
|
||||
|
||||
@Override public int size() {
|
||||
return forwardList.size();
|
||||
}
|
||||
|
||||
@Override boolean isPartialView() {
|
||||
return forwardList.isPartialView();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of {@link List#equals(Object)}.
|
||||
*/
|
||||
static boolean equalsImpl(List<?> list, Object object) {
|
||||
if (object == checkNotNull(list)) {
|
||||
return true;
|
||||
}
|
||||
if (!(object instanceof List)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<?> o = (List<?>) object;
|
||||
|
||||
return list.size() == o.size()
|
||||
&& Iterators.elementsEqual(list.iterator(), o.iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of {@link List#indexOf(Object)}.
|
||||
*/
|
||||
static int indexOfImpl(List<?> list, Object element) {
|
||||
ListIterator<?> listIterator = list.listIterator();
|
||||
while (listIterator.hasNext()) {
|
||||
if (Preconditions.equal(element, listIterator.next())) {
|
||||
return listIterator.previousIndex();
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of {@link List#lastIndexOf(Object)}.
|
||||
*/
|
||||
static int lastIndexOfImpl(List<?> list, Object element) {
|
||||
ListIterator<?> listIterator = list.listIterator(list.size());
|
||||
while (listIterator.hasPrevious()) {
|
||||
if (Preconditions.equal(element, listIterator.previous())) {
|
||||
return listIterator.nextIndex();
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object obj) {
|
||||
return equalsImpl(this, obj);
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
int hashCode = 1;
|
||||
int n = size();
|
||||
for (int i = 0; i < n; i++) {
|
||||
hashCode = 31 * hashCode + get(i).hashCode();
|
||||
|
||||
hashCode = ~~hashCode;
|
||||
// needed to deal with GWT integer overflow
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
/*
|
||||
* Serializes ImmutableLists as their logical contents. This ensures that
|
||||
* implementation types do not leak into the serialized representation.
|
||||
*/
|
||||
static class SerializedForm implements Serializable {
|
||||
final Object[] elements;
|
||||
SerializedForm(Object[] elements) {
|
||||
this.elements = elements;
|
||||
}
|
||||
Object readResolve() {
|
||||
return copyOf(elements);
|
||||
}
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws InvalidObjectException {
|
||||
throw new InvalidObjectException("Use SerializedForm");
|
||||
}
|
||||
|
||||
@Override Object writeReplace() {
|
||||
return new SerializedForm(toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new builder. The generated builder is equivalent to the builder
|
||||
* created by the {@link Builder} constructor.
|
||||
*/
|
||||
public static <E> Builder<E> builder() {
|
||||
return new Builder<E>();
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for creating immutable list instances, especially {@code public
|
||||
* static final} lists ("constant lists"). Example: <pre> {@code
|
||||
*
|
||||
* public static final ImmutableList<Color> GOOGLE_COLORS
|
||||
* = new ImmutableList.Builder<Color>()
|
||||
* .addAll(WEBSAFE_COLORS)
|
||||
* .add(new Color(0, 191, 255))
|
||||
* .build();}</pre>
|
||||
*
|
||||
* <p>Builder instances can be reused; it is safe to call {@link #build} multiple
|
||||
* times to build multiple lists in series. Each new list contains all the
|
||||
* elements of the ones created before it.
|
||||
*
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
public static final class Builder<E> extends ImmutableCollection.ArrayBasedBuilder<E> {
|
||||
/**
|
||||
* Creates a new builder. The returned builder is equivalent to the builder
|
||||
* generated by {@link ImmutableList#builder}.
|
||||
*/
|
||||
public Builder() {
|
||||
this(DEFAULT_INITIAL_CAPACITY);
|
||||
}
|
||||
|
||||
// TODO(user): consider exposing this
|
||||
Builder(int capacity) {
|
||||
super(capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds {@code element} to the {@code ImmutableList}.
|
||||
*
|
||||
* @param element the element to add
|
||||
* @return this {@code Builder} object
|
||||
* @throws NullPointerException if {@code element} is null
|
||||
*/
|
||||
@Override public Builder<E> add(E element) {
|
||||
super.add(element);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds each element of {@code elements} to the {@code ImmutableList}.
|
||||
*
|
||||
* @param elements the {@code Iterable} to add to the {@code ImmutableList}
|
||||
* @return this {@code Builder} object
|
||||
* @throws NullPointerException if {@code elements} is null or contains a
|
||||
* null element
|
||||
*/
|
||||
@Override public Builder<E> addAll(Iterable<? extends E> elements) {
|
||||
super.addAll(elements);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds each element of {@code elements} to the {@code ImmutableList}.
|
||||
*
|
||||
* @param elements the {@code Iterable} to add to the {@code ImmutableList}
|
||||
* @return this {@code Builder} object
|
||||
* @throws NullPointerException if {@code elements} is null or contains a
|
||||
* null element
|
||||
*/
|
||||
@Override public Builder<E> add(E... elements) {
|
||||
super.add(elements);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds each element of {@code elements} to the {@code ImmutableList}.
|
||||
*
|
||||
* @param elements the {@code Iterable} to add to the {@code ImmutableList}
|
||||
* @return this {@code Builder} object
|
||||
* @throws NullPointerException if {@code elements} is null or contains a
|
||||
* null element
|
||||
*/
|
||||
@Override public Builder<E> addAll(Iterator<? extends E> elements) {
|
||||
super.addAll(elements);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a newly-created {@code ImmutableList} based on the contents of
|
||||
* the {@code Builder}.
|
||||
*/
|
||||
@Override public ImmutableList<E> build() {
|
||||
return asImmutableList(contents, size);
|
||||
}
|
||||
}
|
||||
}
|
548
java/src/game/collect/ImmutableMap.java
Normal file
548
java/src/game/collect/ImmutableMap.java
Normal file
|
@ -0,0 +1,548 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.CollectPreconditions.checkEntryNotNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import game.collect.ImmutableMapEntry.TerminalEntry;
|
||||
|
||||
/**
|
||||
* An immutable, hash-based {@link Map} with reliable user-specified iteration
|
||||
* order. Does not permit null keys or values.
|
||||
*
|
||||
* <p>Unlike {@link Collections#unmodifiableMap}, which is a <i>view</i> of a
|
||||
* separate map which can still change, an instance of {@code ImmutableMap}
|
||||
* contains its own data and will <i>never</i> change. {@code ImmutableMap} is
|
||||
* convenient for {@code public static final} maps ("constant maps") and also
|
||||
* lets you easily make a "defensive copy" of a map provided to your class by a
|
||||
* caller.
|
||||
*
|
||||
* <p><i>Performance notes:</i> unlike {@link HashMap}, {@code ImmutableMap} is
|
||||
* not optimized for element types that have slow {@link Object#equals} or
|
||||
* {@link Object#hashCode} implementations. You can get better performance by
|
||||
* having your element type cache its own hash codes, and by making use of the
|
||||
* cached values to short-circuit a slow {@code equals} algorithm.
|
||||
*
|
||||
* <p>See the Guava User Guide article on <a href=
|
||||
* "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
|
||||
* immutable collections</a>.
|
||||
*
|
||||
* @author Jesse Wilson
|
||||
* @author Kevin Bourrillion
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
|
||||
// // we're overriding default serialization
|
||||
public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
|
||||
|
||||
/**
|
||||
* Returns the empty map. This map behaves and performs comparably to
|
||||
* {@link Collections#emptyMap}, and is preferable mainly for consistency
|
||||
* and maintainability of your code.
|
||||
*/
|
||||
public static <K, V> ImmutableMap<K, V> of() {
|
||||
return (ImmutableMap<K, V>)EmptyImmutableMap.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing a single entry. This map behaves and
|
||||
* performs comparably to {@link Collections#singletonMap} but will not accept
|
||||
* a null key or value. It is preferable mainly for consistency and
|
||||
* maintainability of your code.
|
||||
*/
|
||||
// public static <K, V> ImmutableMap<K, V> of(K k1, V v1) {
|
||||
// return ImmutableBiMap.of(k1, v1);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing the given entries, in order.
|
||||
*
|
||||
* @throws IllegalArgumentException if duplicate keys are provided
|
||||
*/
|
||||
public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2) {
|
||||
return new RegularImmutableMap<K, V>(entryOf(k1, v1), entryOf(k2, v2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing the given entries, in order.
|
||||
*
|
||||
* @throws IllegalArgumentException if duplicate keys are provided
|
||||
*/
|
||||
public static <K, V> ImmutableMap<K, V> of(
|
||||
K k1, V v1, K k2, V v2, K k3, V v3) {
|
||||
return new RegularImmutableMap<K, V>(
|
||||
entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing the given entries, in order.
|
||||
*
|
||||
* @throws IllegalArgumentException if duplicate keys are provided
|
||||
*/
|
||||
public static <K, V> ImmutableMap<K, V> of(
|
||||
K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
|
||||
return new RegularImmutableMap<K, V>(
|
||||
entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing the given entries, in order.
|
||||
*
|
||||
* @throws IllegalArgumentException if duplicate keys are provided
|
||||
*/
|
||||
public static <K, V> ImmutableMap<K, V> of(
|
||||
K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
|
||||
return new RegularImmutableMap<K, V>(entryOf(k1, v1),
|
||||
entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4), entryOf(k5, v5));
|
||||
}
|
||||
|
||||
// looking for of() with > 5 entries? Use the builder instead.
|
||||
|
||||
/**
|
||||
* Verifies that {@code key} and {@code value} are non-null, and returns a new
|
||||
* immutable entry with those values.
|
||||
*
|
||||
* <p>A call to {@link Map.Entry#setValue} on the returned entry will always
|
||||
* throw {@link UnsupportedOperationException}.
|
||||
*/
|
||||
static <K, V> TerminalEntry<K, V> entryOf(K key, V value) {
|
||||
checkEntryNotNull(key, value);
|
||||
return new TerminalEntry<K, V>(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new builder. The generated builder is equivalent to the builder
|
||||
* created by the {@link Builder} constructor.
|
||||
*/
|
||||
public static <K, V> Builder<K, V> builder() {
|
||||
return new Builder<K, V>();
|
||||
}
|
||||
|
||||
static void checkNoConflict(boolean safe, String conflictDescription,
|
||||
Entry<?, ?> entry1, Entry<?, ?> entry2) {
|
||||
if (!safe) {
|
||||
throw new IllegalArgumentException(
|
||||
"Multiple entries with same " + conflictDescription + ": " + entry1 + " and " + entry2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for creating immutable map instances, especially {@code public
|
||||
* static final} maps ("constant maps"). Example: <pre> {@code
|
||||
*
|
||||
* static final ImmutableMap<String, Integer> WORD_TO_INT =
|
||||
* new ImmutableMap.Builder<String, Integer>()
|
||||
* .put("one", 1)
|
||||
* .put("two", 2)
|
||||
* .put("three", 3)
|
||||
* .build();}</pre>
|
||||
*
|
||||
* <p>For <i>small</i> immutable maps, the {@code ImmutableMap.of()} methods are
|
||||
* even more convenient.
|
||||
*
|
||||
* <p>Builder instances can be reused - it is safe to call {@link #build}
|
||||
* multiple times to build multiple maps in series. Each map is a superset of
|
||||
* the maps created before it.
|
||||
*
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
public static class Builder<K, V> {
|
||||
TerminalEntry<K, V>[] entries;
|
||||
int size;
|
||||
|
||||
/**
|
||||
* Creates a new builder. The returned builder is equivalent to the builder
|
||||
* generated by {@link ImmutableMap#builder}.
|
||||
*/
|
||||
public Builder() {
|
||||
this(ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY);
|
||||
}
|
||||
|
||||
|
||||
Builder(int initialCapacity) {
|
||||
this.entries = new TerminalEntry[initialCapacity];
|
||||
this.size = 0;
|
||||
}
|
||||
|
||||
private void ensureCapacity(int minCapacity) {
|
||||
if (minCapacity > entries.length) {
|
||||
entries = ObjectArrays.arraysCopyOf(
|
||||
entries, ImmutableCollection.Builder.expandedCapacity(entries.length, minCapacity));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates {@code key} with {@code value} in the built map. Duplicate
|
||||
* keys are not allowed, and will cause {@link #build} to fail.
|
||||
*/
|
||||
public Builder<K, V> put(K key, V value) {
|
||||
ensureCapacity(size + 1);
|
||||
TerminalEntry<K, V> entry = entryOf(key, value);
|
||||
// don't inline this: we want to fail atomically if key or value is null
|
||||
entries[size++] = entry;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given {@code entry} to the map, making it immutable if
|
||||
* necessary. Duplicate keys are not allowed, and will cause {@link #build}
|
||||
* to fail.
|
||||
*
|
||||
* @since 11.0
|
||||
*/
|
||||
public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
|
||||
return put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates all of the given map's keys and values in the built map.
|
||||
* Duplicate keys are not allowed, and will cause {@link #build} to fail.
|
||||
*
|
||||
* @throws NullPointerException if any key or value in {@code map} is null
|
||||
*/
|
||||
public Builder<K, V> putAll(Map<? extends K, ? extends V> map) {
|
||||
ensureCapacity(size + map.size());
|
||||
for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
|
||||
put(entry);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO(kevinb): Should build() and the ImmutableBiMap & ImmutableSortedMap
|
||||
* versions throw an IllegalStateException instead?
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns a newly-created immutable map.
|
||||
*
|
||||
* @throws IllegalArgumentException if duplicate keys were added
|
||||
*/
|
||||
public ImmutableMap<K, V> build() {
|
||||
switch (size) {
|
||||
case 0:
|
||||
return of();
|
||||
// case 1:
|
||||
// return of(entries[0].getKey(), entries[0].getValue());
|
||||
default:
|
||||
return new RegularImmutableMap<K, V>(size, entries);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing the same entries as {@code map}. If
|
||||
* {@code map} somehow contains entries with duplicate keys (for example, if
|
||||
* it is a {@code SortedMap} whose comparator is not <i>consistent with
|
||||
* equals</i>), the results of this method are undefined.
|
||||
*
|
||||
* <p>Despite the method name, this method attempts to avoid actually copying
|
||||
* the data when it is safe to do so. The exact circumstances under which a
|
||||
* copy will or will not be performed are undocumented and subject to change.
|
||||
*
|
||||
* @throws NullPointerException if any key or value in {@code map} is null
|
||||
*/
|
||||
public static <K, V> ImmutableMap<K, V> copyOf(
|
||||
Map<? extends K, ? extends V> map) {
|
||||
if ((map instanceof ImmutableMap)) { // && !(map instanceof ImmutableSortedMap)) {
|
||||
// TODO(user): Make ImmutableMap.copyOf(immutableBiMap) call copyOf()
|
||||
// on the ImmutableMap delegate(), rather than the bimap itself
|
||||
|
||||
// safe since map is not writable
|
||||
ImmutableMap<K, V> kvMap = (ImmutableMap<K, V>) map;
|
||||
if (!kvMap.isPartialView()) {
|
||||
return kvMap;
|
||||
}
|
||||
} else if (map instanceof EnumMap) {
|
||||
return copyOfEnumMapUnsafe(map);
|
||||
}
|
||||
Entry<?, ?>[] entries = map.entrySet().toArray(EMPTY_ENTRY_ARRAY);
|
||||
switch (entries.length) {
|
||||
case 0:
|
||||
return of();
|
||||
// case 1:
|
||||
// // all entries will be Entry<K, V>'s
|
||||
// Entry<K, V> onlyEntry = (Entry<K, V>) entries[0];
|
||||
// return of(onlyEntry.getKey(), onlyEntry.getValue());
|
||||
default:
|
||||
return new RegularImmutableMap<K, V>(entries);
|
||||
}
|
||||
}
|
||||
|
||||
// If the map is an EnumMap, it must have key type K for some <K extends Enum<K>>.
|
||||
|
||||
private static <K, V> ImmutableMap<K, V> copyOfEnumMapUnsafe(Map<? extends K, ? extends V> map) {
|
||||
return copyOfEnumMap((EnumMap) map);
|
||||
}
|
||||
|
||||
private static <K extends Enum<K>, V> ImmutableMap<K, V> copyOfEnumMap(
|
||||
Map<K, ? extends V> original) {
|
||||
EnumMap<K, V> copy = new EnumMap<K, V>(original);
|
||||
for (Map.Entry<?, ?> entry : copy.entrySet()) {
|
||||
checkEntryNotNull(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return ImmutableEnumMap.asImmutable(copy);
|
||||
}
|
||||
|
||||
private static final Entry<?, ?>[] EMPTY_ENTRY_ARRAY = new Entry<?, ?>[0];
|
||||
|
||||
ImmutableMap() {}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the map unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final V put(K k, V v) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the map unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final V remove(Object o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the map unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final void putAll(Map<? extends K, ? extends V> map) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the map unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return get(key) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return values().contains(value);
|
||||
}
|
||||
|
||||
// Overriding to mark it Nullable
|
||||
@Override
|
||||
public abstract V get(Object key);
|
||||
|
||||
private transient ImmutableSet<Entry<K, V>> entrySet;
|
||||
|
||||
/**
|
||||
* Returns an immutable set of the mappings in this map. The entries are in
|
||||
* the same order as the parameters used to build this map.
|
||||
*/
|
||||
@Override
|
||||
public ImmutableSet<Entry<K, V>> entrySet() {
|
||||
ImmutableSet<Entry<K, V>> result = entrySet;
|
||||
return (result == null) ? entrySet = createEntrySet() : result;
|
||||
}
|
||||
|
||||
abstract ImmutableSet<Entry<K, V>> createEntrySet();
|
||||
|
||||
private transient ImmutableSet<K> keySet;
|
||||
|
||||
/**
|
||||
* Returns an immutable set of the keys in this map. These keys are in
|
||||
* the same order as the parameters used to build this map.
|
||||
*/
|
||||
@Override
|
||||
public ImmutableSet<K> keySet() {
|
||||
ImmutableSet<K> result = keySet;
|
||||
return (result == null) ? keySet = createKeySet() : result;
|
||||
}
|
||||
|
||||
ImmutableSet<K> createKeySet() {
|
||||
return new ImmutableMapKeySet<K, V>(this);
|
||||
}
|
||||
|
||||
private transient ImmutableCollection<V> values;
|
||||
|
||||
/**
|
||||
* Returns an immutable collection of the values in this map. The values are
|
||||
* in the same order as the parameters used to build this map.
|
||||
*/
|
||||
@Override
|
||||
public ImmutableCollection<V> values() {
|
||||
ImmutableCollection<V> result = values;
|
||||
return (result == null) ? values = new ImmutableMapValues<K, V>(this) : result;
|
||||
}
|
||||
|
||||
// cached so that this.multimapView().inverse() only computes inverse once
|
||||
// private transient ImmutableSetMultimap<K, V> multimapView;
|
||||
|
||||
/**
|
||||
* Returns a multimap view of the map.
|
||||
*
|
||||
* @since 14.0
|
||||
*/
|
||||
// @Beta
|
||||
// public ImmutableSetMultimap<K, V> asMultimap() {
|
||||
// ImmutableSetMultimap<K, V> result = multimapView;
|
||||
// return (result == null) ? (multimapView = createMultimapView()) : result;
|
||||
// }
|
||||
//
|
||||
// private ImmutableSetMultimap<K, V> createMultimapView() {
|
||||
// ImmutableMap<K, ImmutableSet<V>> map = viewMapValuesAsSingletonSets();
|
||||
// return new ImmutableSetMultimap<K, V>(map, map.size(), null);
|
||||
// }
|
||||
|
||||
// private ImmutableMap<K, ImmutableSet<V>> viewMapValuesAsSingletonSets() {
|
||||
// return new MapViewOfValuesAsSingletonSets<K, V>(this);
|
||||
// }
|
||||
//
|
||||
// private static final class MapViewOfValuesAsSingletonSets<K, V>
|
||||
// extends ImmutableMap<K, ImmutableSet<V>> {
|
||||
// private final ImmutableMap<K, V> delegate;
|
||||
//
|
||||
// MapViewOfValuesAsSingletonSets(ImmutableMap<K, V> delegate) {
|
||||
// this.delegate = checkNotNull(delegate);
|
||||
// }
|
||||
//
|
||||
// @Override public int size() {
|
||||
// return delegate.size();
|
||||
// }
|
||||
//
|
||||
// @Override public boolean containsKey(Object key) {
|
||||
// return delegate.containsKey(key);
|
||||
// }
|
||||
//
|
||||
// @Override public ImmutableSet<V> get(Object key) {
|
||||
// V outerValue = delegate.get(key);
|
||||
// return (outerValue == null) ? null : ImmutableSet.of(outerValue);
|
||||
// }
|
||||
//
|
||||
// @Override boolean isPartialView() {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// @Override ImmutableSet<Entry<K, ImmutableSet<V>>> createEntrySet() {
|
||||
// return new ImmutableMapEntrySet<K, ImmutableSet<V>>() {
|
||||
// @Override ImmutableMap<K, ImmutableSet<V>> map() {
|
||||
// return MapViewOfValuesAsSingletonSets.this;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public UnmodifiableIterator<Entry<K, ImmutableSet<V>>> iterator() {
|
||||
// final Iterator<Entry<K, V>> backingIterator = delegate.entrySet().iterator();
|
||||
// return new UnmodifiableIterator<Entry<K, ImmutableSet<V>>>() {
|
||||
// @Override public boolean hasNext() {
|
||||
// return backingIterator.hasNext();
|
||||
// }
|
||||
//
|
||||
// @Override public Entry<K, ImmutableSet<V>> next() {
|
||||
// final Entry<K, V> backingEntry = backingIterator.next();
|
||||
// return new AbstractMapEntry<K, ImmutableSet<V>>() {
|
||||
// @Override public K getKey() {
|
||||
// return backingEntry.getKey();
|
||||
// }
|
||||
//
|
||||
// @Override public ImmutableSet<V> getValue() {
|
||||
// return ImmutableSet.of(backingEntry.getValue());
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override public boolean equals(Object object) {
|
||||
return Maps.equalsImpl(this, object);
|
||||
}
|
||||
|
||||
abstract boolean isPartialView();
|
||||
|
||||
@Override public int hashCode() {
|
||||
// not caching hash code since it could change if map values are mutable
|
||||
// in a way that modifies their hash codes
|
||||
return entrySet().hashCode();
|
||||
}
|
||||
|
||||
// @Override public String toString() {
|
||||
// return Maps.toStringImpl(this);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Serialized type for all ImmutableMap instances. It captures the logical
|
||||
* contents and they are reconstructed using public factory methods. This
|
||||
* ensures that the implementation types remain as implementation details.
|
||||
*/
|
||||
// static class SerializedForm implements Serializable {
|
||||
// private final Object[] keys;
|
||||
// private final Object[] values;
|
||||
// SerializedForm(ImmutableMap<?, ?> map) {
|
||||
// keys = new Object[map.size()];
|
||||
// values = new Object[map.size()];
|
||||
// int i = 0;
|
||||
// for (Entry<?, ?> entry : map.entrySet()) {
|
||||
// keys[i] = entry.getKey();
|
||||
// values[i] = entry.getValue();
|
||||
// i++;
|
||||
// }
|
||||
// }
|
||||
// Object readResolve() {
|
||||
// Builder<Object, Object> builder = new Builder<Object, Object>();
|
||||
// return createMap(builder);
|
||||
// }
|
||||
// Object createMap(Builder<Object, Object> builder) {
|
||||
// for (int i = 0; i < keys.length; i++) {
|
||||
// builder.put(keys[i], values[i]);
|
||||
// }
|
||||
// return builder.build();
|
||||
// }
|
||||
// private static final long serialVersionUID = 0;
|
||||
// }
|
||||
//
|
||||
// Object writeReplace() {
|
||||
// return new SerializedForm(this);
|
||||
// }
|
||||
}
|
68
java/src/game/collect/ImmutableMapEntry.java
Normal file
68
java/src/game/collect/ImmutableMapEntry.java
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (C) 2013 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.CollectPreconditions.checkEntryNotNull;
|
||||
|
||||
/**
|
||||
* Implementation of {@code Map.Entry} for {@link ImmutableMap} that adds extra methods to traverse
|
||||
* hash buckets for the key and the value. This allows reuse in {@link RegularImmutableMap} and
|
||||
* {@link RegularImmutableBiMap}, which don't have to recopy the entries created by their
|
||||
* {@code Builder} implementations.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
|
||||
abstract class ImmutableMapEntry<K, V> extends ImmutableEntry<K, V> {
|
||||
ImmutableMapEntry(K key, V value) {
|
||||
super(key, value);
|
||||
checkEntryNotNull(key, value);
|
||||
}
|
||||
|
||||
ImmutableMapEntry(ImmutableMapEntry<K, V> contents) {
|
||||
super(contents.getKey(), contents.getValue());
|
||||
// null check would be redundant
|
||||
}
|
||||
|
||||
|
||||
abstract ImmutableMapEntry<K, V> getNextInKeyBucket();
|
||||
|
||||
|
||||
abstract ImmutableMapEntry<K, V> getNextInValueBucket();
|
||||
|
||||
static final class TerminalEntry<K, V> extends ImmutableMapEntry<K, V> {
|
||||
TerminalEntry(ImmutableMapEntry<K, V> contents) {
|
||||
super(contents);
|
||||
}
|
||||
|
||||
TerminalEntry(K key, V value) {
|
||||
super(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
ImmutableMapEntry<K, V> getNextInKeyBucket() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
ImmutableMapEntry<K, V> getNextInValueBucket() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
71
java/src/game/collect/ImmutableMapEntrySet.java
Normal file
71
java/src/game/collect/ImmutableMapEntrySet.java
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* {@code entrySet()} implementation for {@link ImmutableMap}.
|
||||
*
|
||||
* @author Jesse Wilson
|
||||
* @author Kevin Bourrillion
|
||||
*/
|
||||
|
||||
abstract class ImmutableMapEntrySet<K, V> extends ImmutableSet<Entry<K, V>> {
|
||||
ImmutableMapEntrySet() {}
|
||||
|
||||
abstract ImmutableMap<K, V> map();
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return map().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object object) {
|
||||
if (object instanceof Entry) {
|
||||
Entry<?, ?> entry = (Entry<?, ?>) object;
|
||||
V value = map().get(entry.getKey());
|
||||
return value != null && value.equals(entry.getValue());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return map().isPartialView();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
Object writeReplace() {
|
||||
return new EntrySetSerializedForm<K, V>(map());
|
||||
}
|
||||
|
||||
|
||||
private static class EntrySetSerializedForm<K, V> implements Serializable {
|
||||
final ImmutableMap<K, V> map;
|
||||
EntrySetSerializedForm(ImmutableMap<K, V> map) {
|
||||
this.map = map;
|
||||
}
|
||||
Object readResolve() {
|
||||
return map.entrySet();
|
||||
}
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
}
|
90
java/src/game/collect/ImmutableMapKeySet.java
Normal file
90
java/src/game/collect/ImmutableMapKeySet.java
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* {@code keySet()} implementation for {@link ImmutableMap}.
|
||||
*
|
||||
* @author Jesse Wilson
|
||||
* @author Kevin Bourrillion
|
||||
*/
|
||||
|
||||
final class ImmutableMapKeySet<K, V> extends ImmutableSet<K> {
|
||||
private final ImmutableMap<K, V> map;
|
||||
|
||||
ImmutableMapKeySet(ImmutableMap<K, V> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnmodifiableIterator<K> iterator() {
|
||||
return asList().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object object) {
|
||||
return map.containsKey(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableList<K> createAsList() {
|
||||
final ImmutableList<Entry<K, V>> entryList = map.entrySet().asList();
|
||||
return new ImmutableAsList<K>() {
|
||||
|
||||
@Override
|
||||
public K get(int index) {
|
||||
return entryList.get(index).getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableCollection<K> delegateCollection() {
|
||||
return ImmutableMapKeySet.this;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override Object writeReplace() {
|
||||
return new KeySetSerializedForm<K>(map);
|
||||
}
|
||||
|
||||
|
||||
private static class KeySetSerializedForm<K> implements Serializable {
|
||||
final ImmutableMap<K, ?> map;
|
||||
KeySetSerializedForm(ImmutableMap<K, ?> map) {
|
||||
this.map = map;
|
||||
}
|
||||
Object readResolve() {
|
||||
return map.keySet();
|
||||
}
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
}
|
88
java/src/game/collect/ImmutableMapValues.java
Normal file
88
java/src/game/collect/ImmutableMapValues.java
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* {@code values()} implementation for {@link ImmutableMap}.
|
||||
*
|
||||
* @author Jesse Wilson
|
||||
* @author Kevin Bourrillion
|
||||
*/
|
||||
|
||||
final class ImmutableMapValues<K, V> extends ImmutableCollection<V> {
|
||||
private final ImmutableMap<K, V> map;
|
||||
|
||||
ImmutableMapValues(ImmutableMap<K, V> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnmodifiableIterator<V> iterator() {
|
||||
return Maps.valueIterator(map.entrySet().iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object object) {
|
||||
return object != null && Iterators.contains(iterator(), object);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableList<V> createAsList() {
|
||||
final ImmutableList<Entry<K, V>> entryList = map.entrySet().asList();
|
||||
return new ImmutableAsList<V>() {
|
||||
@Override
|
||||
public V get(int index) {
|
||||
return entryList.get(index).getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableCollection<V> delegateCollection() {
|
||||
return ImmutableMapValues.this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@Override Object writeReplace() {
|
||||
return new SerializedForm<V>(map);
|
||||
}
|
||||
|
||||
|
||||
private static class SerializedForm<V> implements Serializable {
|
||||
final ImmutableMap<?, V> map;
|
||||
SerializedForm(ImmutableMap<?, V> map) {
|
||||
this.map = map;
|
||||
}
|
||||
Object readResolve() {
|
||||
return map.values();
|
||||
}
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
}
|
533
java/src/game/collect/ImmutableSet.java
Normal file
533
java/src/game/collect/ImmutableSet.java
Normal file
|
@ -0,0 +1,533 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.ObjectArrays.checkElementNotNull;
|
||||
import static game.collect.Preconditions.checkArgument;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A high-performance, immutable {@code Set} with reliable, user-specified
|
||||
* iteration order. Does not permit null elements.
|
||||
*
|
||||
* <p>Unlike {@link Collections#unmodifiableSet}, which is a <i>view</i> of a
|
||||
* separate collection that can still change, an instance of this class contains
|
||||
* its own private data and will <i>never</i> change. This class is convenient
|
||||
* for {@code public static final} sets ("constant sets") and also lets you
|
||||
* easily make a "defensive copy" of a set provided to your class by a caller.
|
||||
*
|
||||
* <p><b>Warning:</b> Like most sets, an {@code ImmutableSet} will not function
|
||||
* correctly if an element is modified after being placed in the set. For this
|
||||
* reason, and to avoid general confusion, it is strongly recommended to place
|
||||
* only immutable objects into this collection.
|
||||
*
|
||||
* <p>This class has been observed to perform significantly better than {@link
|
||||
* HashSet} for objects with very fast {@link Object#hashCode} implementations
|
||||
* (as a well-behaved immutable object should). While this class's factory
|
||||
* methods create hash-based instances, the {@link ImmutableSortedSet} subclass
|
||||
* performs binary searches instead.
|
||||
*
|
||||
* <p><b>Note:</b> Although this class is not final, it cannot be subclassed
|
||||
* outside its package as it has no public or protected constructors. Thus,
|
||||
* instances of this type are guaranteed to be immutable.
|
||||
*
|
||||
* <p>See the Guava User Guide article on <a href=
|
||||
* "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
|
||||
* immutable collections</a>.
|
||||
*
|
||||
* @see ImmutableList
|
||||
* @see ImmutableMap
|
||||
* @author Kevin Bourrillion
|
||||
* @author Nick Kralevich
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
|
||||
// we're overriding default serialization
|
||||
public abstract class ImmutableSet<E> extends ImmutableCollection<E>
|
||||
implements Set<E> {
|
||||
/**
|
||||
* Returns the empty immutable set. This set behaves and performs comparably
|
||||
* to {@link Collections#emptySet}, and is preferable mainly for consistency
|
||||
* and maintainability of your code.
|
||||
*/
|
||||
// Casting to any type is safe because the set will never hold any elements.
|
||||
|
||||
public static <E> ImmutableSet<E> of() {
|
||||
return (ImmutableSet<E>) EmptyImmutableSet.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing a single element. This set behaves and
|
||||
* performs comparably to {@link Collections#singleton}, but will not accept
|
||||
* a null element. It is preferable mainly for consistency and
|
||||
* maintainability of your code.
|
||||
*/
|
||||
// public static <E> ImmutableSet<E> of(E element) {
|
||||
// return new SingletonImmutableSet<E>(element);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing the given elements, in order. Repeated
|
||||
* occurrences of an element (according to {@link Object#equals}) after the
|
||||
* first are ignored.
|
||||
*
|
||||
* @throws NullPointerException if any element is null
|
||||
*/
|
||||
public static <E> ImmutableSet<E> of(E e1, E e2) {
|
||||
return construct(2, e1, e2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing the given elements, in order. Repeated
|
||||
* occurrences of an element (according to {@link Object#equals}) after the
|
||||
* first are ignored.
|
||||
*
|
||||
* @throws NullPointerException if any element is null
|
||||
*/
|
||||
public static <E> ImmutableSet<E> of(E e1, E e2, E e3) {
|
||||
return construct(3, e1, e2, e3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing the given elements, in order. Repeated
|
||||
* occurrences of an element (according to {@link Object#equals}) after the
|
||||
* first are ignored.
|
||||
*
|
||||
* @throws NullPointerException if any element is null
|
||||
*/
|
||||
public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4) {
|
||||
return construct(4, e1, e2, e3, e4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing the given elements, in order. Repeated
|
||||
* occurrences of an element (according to {@link Object#equals}) after the
|
||||
* first are ignored.
|
||||
*
|
||||
* @throws NullPointerException if any element is null
|
||||
*/
|
||||
public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5) {
|
||||
return construct(5, e1, e2, e3, e4, e5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing the given elements, in order. Repeated
|
||||
* occurrences of an element (according to {@link Object#equals}) after the
|
||||
* first are ignored.
|
||||
*
|
||||
* @throws NullPointerException if any element is null
|
||||
* @since 3.0 (source-compatible since 2.0)
|
||||
*/
|
||||
public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5, E e6,
|
||||
E... others) {
|
||||
final int paramCount = 6;
|
||||
Object[] elements = new Object[paramCount + others.length];
|
||||
elements[0] = e1;
|
||||
elements[1] = e2;
|
||||
elements[2] = e3;
|
||||
elements[3] = e4;
|
||||
elements[4] = e5;
|
||||
elements[5] = e6;
|
||||
System.arraycopy(others, 0, elements, paramCount, others.length);
|
||||
return construct(elements.length, elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an {@code ImmutableSet} from the first {@code n} elements of the specified array.
|
||||
* If {@code k} is the size of the returned {@code ImmutableSet}, then the unique elements of
|
||||
* {@code elements} will be in the first {@code k} positions, and {@code elements[i] == null} for
|
||||
* {@code k <= i < n}.
|
||||
*
|
||||
* <p>This may modify {@code elements}. Additionally, if {@code n == elements.length} and
|
||||
* {@code elements} contains no duplicates, {@code elements} may be used without copying in the
|
||||
* returned {@code ImmutableSet}, in which case it may no longer be modified.
|
||||
*
|
||||
* <p>{@code elements} may contain only values of type {@code E}.
|
||||
*
|
||||
* @throws NullPointerException if any of the first {@code n} elements of {@code elements} is
|
||||
* null
|
||||
*/
|
||||
private static <E> ImmutableSet<E> construct(int n, Object... elements) {
|
||||
switch (n) {
|
||||
case 0:
|
||||
return of();
|
||||
// case 1:
|
||||
// // safe; elements contains only E's
|
||||
// E elem = (E) elements[0];
|
||||
// return of(elem);
|
||||
default:
|
||||
// continue below to handle the general case
|
||||
}
|
||||
int tableSize = chooseTableSize(n);
|
||||
Object[] table = new Object[tableSize];
|
||||
int mask = tableSize - 1;
|
||||
int hashCode = 0;
|
||||
int uniques = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
Object element = checkElementNotNull(elements[i], i);
|
||||
int hash = element.hashCode();
|
||||
for (int j = Hashing.smear(hash); ; j++) {
|
||||
int index = j & mask;
|
||||
Object value = table[index];
|
||||
if (value == null) {
|
||||
// Came to an empty slot. Put the element here.
|
||||
elements[uniques++] = element;
|
||||
table[index] = element;
|
||||
hashCode += hash;
|
||||
break;
|
||||
} else if (value.equals(element)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Arrays.fill(elements, uniques, n, null);
|
||||
// if (uniques == 1) {
|
||||
// // There is only one element or elements are all duplicates
|
||||
// // we are careful to only pass in E
|
||||
// E element = (E) elements[0];
|
||||
// return new SingletonImmutableSet<E>(element, hashCode);
|
||||
// } else
|
||||
if (tableSize != chooseTableSize(uniques)) {
|
||||
// Resize the table when the array includes too many duplicates.
|
||||
// when this happens, we have already made a copy
|
||||
return construct(uniques, elements);
|
||||
} else {
|
||||
Object[] uniqueElements = (uniques < elements.length)
|
||||
? ObjectArrays.arraysCopyOf(elements, uniques)
|
||||
: elements;
|
||||
return new RegularImmutableSet<E>(uniqueElements, hashCode, table, mask);
|
||||
}
|
||||
}
|
||||
|
||||
// We use power-of-2 tables, and this is the highest int that's a power of 2
|
||||
static final int MAX_TABLE_SIZE = 1 << (Integer.SIZE - 2);
|
||||
|
||||
// Represents how tightly we can pack things, as a maximum.
|
||||
private static final double DESIRED_LOAD_FACTOR = 0.7;
|
||||
|
||||
// If the set has this many elements, it will "max out" the table size
|
||||
private static final int CUTOFF =
|
||||
(int) (MAX_TABLE_SIZE * DESIRED_LOAD_FACTOR);
|
||||
|
||||
/**
|
||||
* Returns an array size suitable for the backing array of a hash table that
|
||||
* uses open addressing with linear probing in its implementation. The
|
||||
* returned size is the smallest power of two that can hold setSize elements
|
||||
* with the desired load factor.
|
||||
*
|
||||
* <p>Do not call this method with setSize < 2.
|
||||
*/
|
||||
// @VisibleForTesting
|
||||
static int chooseTableSize(int setSize) {
|
||||
setSize = setSize < 2 ? 2 : setSize;
|
||||
// Correct the size for open addressing to match desired load factor.
|
||||
if (setSize < CUTOFF) {
|
||||
// Round up to the next highest power of 2.
|
||||
int tableSize = Integer.highestOneBit(setSize - 1) << 1;
|
||||
while (tableSize * DESIRED_LOAD_FACTOR < setSize) {
|
||||
tableSize <<= 1;
|
||||
}
|
||||
return tableSize;
|
||||
}
|
||||
|
||||
// The table can't be completely full or we'll get infinite reprobes
|
||||
checkArgument(setSize < MAX_TABLE_SIZE, "collection too large");
|
||||
return MAX_TABLE_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing the given elements, in order. Repeated
|
||||
* occurrences of an element (according to {@link Object#equals}) after the
|
||||
* first are ignored.
|
||||
*
|
||||
* @throws NullPointerException if any of {@code elements} is null
|
||||
* @since 3.0
|
||||
*/
|
||||
public static <E> ImmutableSet<E> copyOf(E[] elements) {
|
||||
switch (elements.length) {
|
||||
case 0:
|
||||
return of();
|
||||
// case 1:
|
||||
// return of(elements[0]);
|
||||
default:
|
||||
return construct(elements.length, elements.clone());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing the given elements, in order. Repeated
|
||||
* occurrences of an element (according to {@link Object#equals}) after the
|
||||
* first are ignored. This method iterates over {@code elements} at most once.
|
||||
*
|
||||
* <p>Note that if {@code s} is a {@code Set<String>}, then {@code
|
||||
* ImmutableSet.copyOf(s)} returns an {@code ImmutableSet<String>} containing
|
||||
* each of the strings in {@code s}, while {@code ImmutableSet.of(s)} returns
|
||||
* a {@code ImmutableSet<Set<String>>} containing one element (the given set
|
||||
* itself).
|
||||
*
|
||||
* <p>Despite the method name, this method attempts to avoid actually copying
|
||||
* the data when it is safe to do so. The exact circumstances under which a
|
||||
* copy will or will not be performed are undocumented and subject to change.
|
||||
*
|
||||
* @throws NullPointerException if any of {@code elements} is null
|
||||
*/
|
||||
public static <E> ImmutableSet<E> copyOf(Iterable<? extends E> elements) {
|
||||
return (elements instanceof Collection)
|
||||
? copyOf(Filter.cast(elements))
|
||||
: copyOf(elements.iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing the given elements, in order. Repeated
|
||||
* occurrences of an element (according to {@link Object#equals}) after the
|
||||
* first are ignored.
|
||||
*
|
||||
* @throws NullPointerException if any of {@code elements} is null
|
||||
*/
|
||||
public static <E> ImmutableSet<E> copyOf(Iterator<? extends E> elements) {
|
||||
// We special-case for 0 or 1 elements, but anything further is madness.
|
||||
if (!elements.hasNext()) {
|
||||
return of();
|
||||
}
|
||||
// E first = elements.next();
|
||||
// if (!elements.hasNext()) {
|
||||
// return of(first);
|
||||
// } else {
|
||||
return new ImmutableSet.Builder<E>()
|
||||
// .add(first)
|
||||
.addAll(elements)
|
||||
.build();
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing the given elements, in order. Repeated
|
||||
* occurrences of an element (according to {@link Object#equals}) after the
|
||||
* first are ignored. This method iterates over {@code elements} at most
|
||||
* once.
|
||||
*
|
||||
* <p>Note that if {@code s} is a {@code Set<String>}, then {@code
|
||||
* ImmutableSet.copyOf(s)} returns an {@code ImmutableSet<String>} containing
|
||||
* each of the strings in {@code s}, while {@code ImmutableSet.of(s)} returns
|
||||
* a {@code ImmutableSet<Set<String>>} containing one element (the given set
|
||||
* itself).
|
||||
*
|
||||
* <p><b>Note:</b> Despite what the method name suggests, {@code copyOf} will
|
||||
* return constant-space views, rather than linear-space copies, of some
|
||||
* inputs known to be immutable. For some other immutable inputs, such as key
|
||||
* sets of an {@code ImmutableMap}, it still performs a copy in order to avoid
|
||||
* holding references to the values of the map. The heuristics used in this
|
||||
* decision are undocumented and subject to change except that:
|
||||
* <ul>
|
||||
* <li>A full copy will be done of any {@code ImmutableSortedSet}.</li>
|
||||
* <li>{@code ImmutableSet.copyOf()} is idempotent with respect to pointer
|
||||
* equality.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>This method is safe to use even when {@code elements} is a synchronized
|
||||
* or concurrent collection that is currently being modified by another
|
||||
* thread.
|
||||
*
|
||||
* @throws NullPointerException if any of {@code elements} is null
|
||||
* @since 7.0 (source-compatible since 2.0)
|
||||
*/
|
||||
public static <E> ImmutableSet<E> copyOf(Collection<? extends E> elements) {
|
||||
/*
|
||||
* TODO(user): consider checking for ImmutableAsList here
|
||||
* TODO(user): consider checking for Multiset here
|
||||
*/
|
||||
if (elements instanceof ImmutableSet) {
|
||||
// && !(elements instanceof ImmutableSortedSet)) {
|
||||
// all supported methods are covariant
|
||||
ImmutableSet<E> set = (ImmutableSet<E>) elements;
|
||||
if (!set.isPartialView()) {
|
||||
return set;
|
||||
}
|
||||
} else if (elements instanceof EnumSet) {
|
||||
return copyOfEnumSet((EnumSet) elements);
|
||||
}
|
||||
Object[] array = elements.toArray();
|
||||
return construct(array.length, array);
|
||||
}
|
||||
|
||||
private static <E extends Enum<E>> ImmutableSet<E> copyOfEnumSet(
|
||||
EnumSet<E> enumSet) {
|
||||
return ImmutableEnumSet.asImmutable(EnumSet.copyOf(enumSet));
|
||||
}
|
||||
|
||||
ImmutableSet() {}
|
||||
|
||||
/** Returns {@code true} if the {@code hashCode()} method runs quickly. */
|
||||
boolean isHashCodeFast() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object object) {
|
||||
if (object == this) {
|
||||
return true;
|
||||
} else if (object instanceof ImmutableSet
|
||||
&& isHashCodeFast()
|
||||
&& ((ImmutableSet<?>) object).isHashCodeFast()
|
||||
&& hashCode() != object.hashCode()) {
|
||||
return false;
|
||||
}
|
||||
return Sets.equalsImpl(this, object);
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
return Sets.hashCodeImpl(this);
|
||||
}
|
||||
|
||||
// This declaration is needed to make Set.iterator() and
|
||||
// ImmutableCollection.iterator() consistent.
|
||||
@Override public abstract UnmodifiableIterator<E> iterator();
|
||||
|
||||
/*
|
||||
* This class is used to serialize all ImmutableSet instances, except for
|
||||
* ImmutableEnumSet/ImmutableSortedSet, regardless of implementation type. It
|
||||
* captures their "logical contents" and they are reconstructed using public
|
||||
* static factories. This is necessary to ensure that the existence of a
|
||||
* particular implementation type is an implementation detail.
|
||||
*/
|
||||
private static class SerializedForm implements Serializable {
|
||||
final Object[] elements;
|
||||
SerializedForm(Object[] elements) {
|
||||
this.elements = elements;
|
||||
}
|
||||
Object readResolve() {
|
||||
return copyOf(elements);
|
||||
}
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
@Override Object writeReplace() {
|
||||
return new SerializedForm(toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new builder. The generated builder is equivalent to the builder
|
||||
* created by the {@link Builder} constructor.
|
||||
*/
|
||||
public static <E> Builder<E> builder() {
|
||||
return new Builder<E>();
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for creating immutable set instances, especially {@code public
|
||||
* static final} sets ("constant sets"). Example: <pre> {@code
|
||||
*
|
||||
* public static final ImmutableSet<Color> GOOGLE_COLORS =
|
||||
* new ImmutableSet.Builder<Color>()
|
||||
* .addAll(WEBSAFE_COLORS)
|
||||
* .add(new Color(0, 191, 255))
|
||||
* .build();}</pre>
|
||||
*
|
||||
* <p>Builder instances can be reused; it is safe to call {@link #build} multiple
|
||||
* times to build multiple sets in series. Each set is a superset of the set
|
||||
* created before it.
|
||||
*
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
public static class Builder<E> extends ImmutableCollection.ArrayBasedBuilder<E> {
|
||||
|
||||
/**
|
||||
* Creates a new builder. The returned builder is equivalent to the builder
|
||||
* generated by {@link ImmutableSet#builder}.
|
||||
*/
|
||||
public Builder() {
|
||||
this(DEFAULT_INITIAL_CAPACITY);
|
||||
}
|
||||
|
||||
Builder(int capacity) {
|
||||
super(capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds {@code element} to the {@code ImmutableSet}. If the {@code
|
||||
* ImmutableSet} already contains {@code element}, then {@code add} has no
|
||||
* effect (only the previously added element is retained).
|
||||
*
|
||||
* @param element the element to add
|
||||
* @return this {@code Builder} object
|
||||
* @throws NullPointerException if {@code element} is null
|
||||
*/
|
||||
@Override public Builder<E> add(E element) {
|
||||
super.add(element);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds each element of {@code elements} to the {@code ImmutableSet},
|
||||
* ignoring duplicate elements (only the first duplicate element is added).
|
||||
*
|
||||
* @param elements the elements to add
|
||||
* @return this {@code Builder} object
|
||||
* @throws NullPointerException if {@code elements} is null or contains a
|
||||
* null element
|
||||
*/
|
||||
@Override public Builder<E> add(E... elements) {
|
||||
super.add(elements);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds each element of {@code elements} to the {@code ImmutableSet},
|
||||
* ignoring duplicate elements (only the first duplicate element is added).
|
||||
*
|
||||
* @param elements the {@code Iterable} to add to the {@code ImmutableSet}
|
||||
* @return this {@code Builder} object
|
||||
* @throws NullPointerException if {@code elements} is null or contains a
|
||||
* null element
|
||||
*/
|
||||
@Override public Builder<E> addAll(Iterable<? extends E> elements) {
|
||||
super.addAll(elements);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds each element of {@code elements} to the {@code ImmutableSet},
|
||||
* ignoring duplicate elements (only the first duplicate element is added).
|
||||
*
|
||||
* @param elements the elements to add to the {@code ImmutableSet}
|
||||
* @return this {@code Builder} object
|
||||
* @throws NullPointerException if {@code elements} is null or contains a
|
||||
* null element
|
||||
*/
|
||||
@Override public Builder<E> addAll(Iterator<? extends E> elements) {
|
||||
super.addAll(elements);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a newly-created {@code ImmutableSet} based on the contents of
|
||||
* the {@code Builder}.
|
||||
*/
|
||||
@Override public ImmutableSet<E> build() {
|
||||
ImmutableSet<E> result = construct(size, contents);
|
||||
// construct has the side effect of deduping contents, so we update size
|
||||
// accordingly.
|
||||
size = result.size();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
436
java/src/game/collect/ImmutableTable.java
Normal file
436
java/src/game/collect/ImmutableTable.java
Normal file
|
@ -0,0 +1,436 @@
|
|||
/*
|
||||
* Copyright (C) 2009 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An immutable {@link Table} with reliable user-specified iteration order.
|
||||
* Does not permit null keys or values.
|
||||
*
|
||||
* <p><b>Note</b>: Although this class is not final, it cannot be subclassed as
|
||||
* it has no public or protected constructors. Thus, instances of this class are
|
||||
* guaranteed to be immutable.
|
||||
*
|
||||
* <p>See the Guava User Guide article on <a href=
|
||||
* "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
|
||||
* immutable collections</a>.
|
||||
*
|
||||
* @author Gregory Kick
|
||||
* @since 11.0
|
||||
*/
|
||||
|
||||
// TODO(gak): make serializable
|
||||
public abstract class ImmutableTable<R, C, V> extends AbstractTable<R, C, V> {
|
||||
private static final ImmutableTable<Object, Object, Object> EMPTY
|
||||
= new SparseImmutableTable<Object, Object, Object>(
|
||||
ImmutableList.<Cell<Object, Object, Object>>of(),
|
||||
ImmutableSet.of(), ImmutableSet.of());
|
||||
|
||||
/** Returns an empty immutable table. */
|
||||
|
||||
public static <R, C, V> ImmutableTable<R, C, V> of() {
|
||||
return (ImmutableTable<R, C, V>) EMPTY;
|
||||
}
|
||||
|
||||
// /** Returns an immutable table containing a single cell. */
|
||||
// public static <R, C, V> ImmutableTable<R, C, V> of(R rowKey,
|
||||
// C columnKey, V value) {
|
||||
// return new SingletonImmutableTable<R, C, V>(rowKey, columnKey, value);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns an immutable copy of the provided table.
|
||||
*
|
||||
* <p>The {@link Table#cellSet()} iteration order of the provided table
|
||||
* determines the iteration ordering of all views in the returned table. Note
|
||||
* that some views of the original table and the copied table may have
|
||||
* different iteration orders. For more control over the ordering, create a
|
||||
* {@link Builder} and call {@link Builder#orderRowsBy},
|
||||
* {@link Builder#orderColumnsBy}, and {@link Builder#putAll}
|
||||
*
|
||||
* <p>Despite the method name, this method attempts to avoid actually copying
|
||||
* the data when it is safe to do so. The exact circumstances under which a
|
||||
* copy will or will not be performed are undocumented and subject to change.
|
||||
*/
|
||||
public static <R, C, V> ImmutableTable<R, C, V> copyOf(
|
||||
Table<? extends R, ? extends C, ? extends V> table) {
|
||||
if (table instanceof ImmutableTable) {
|
||||
|
||||
ImmutableTable<R, C, V> parameterizedTable
|
||||
= (ImmutableTable<R, C, V>) table;
|
||||
return parameterizedTable;
|
||||
} else {
|
||||
int size = table.size();
|
||||
switch (size) {
|
||||
case 0:
|
||||
return of();
|
||||
// case 1:
|
||||
// Cell<? extends R, ? extends C, ? extends V> onlyCell
|
||||
// = Iterables.getOnlyElement(table.cellSet());
|
||||
// return ImmutableTable.<R, C, V>of(onlyCell.getRowKey(),
|
||||
// onlyCell.getColumnKey(), onlyCell.getValue());
|
||||
default:
|
||||
ImmutableSet.Builder<Cell<R, C, V>> cellSetBuilder
|
||||
= ImmutableSet.builder();
|
||||
for (Cell<? extends R, ? extends C, ? extends V> cell :
|
||||
table.cellSet()) {
|
||||
/*
|
||||
* Must cast to be able to create a Cell<R, C, V> rather than a
|
||||
* Cell<? extends R, ? extends C, ? extends V>
|
||||
*/
|
||||
cellSetBuilder.add(cellOf((R) cell.getRowKey(),
|
||||
(C) cell.getColumnKey(), (V) cell.getValue()));
|
||||
}
|
||||
return RegularImmutableTable.forCells(cellSetBuilder.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new builder. The generated builder is equivalent to the builder
|
||||
* created by the {@link Builder#ImmutableTable.Builder()} constructor.
|
||||
*/
|
||||
// public static <R, C, V> Builder<R, C, V> builder() {
|
||||
// return new Builder<R, C, V>();
|
||||
// }
|
||||
|
||||
public static <R, C, V> Cell<R, C, V> immutableCell(
|
||||
R rowKey, C columnKey, V value) {
|
||||
return new ImmutableCell<R, C, V>(rowKey, columnKey, value);
|
||||
}
|
||||
|
||||
static final class ImmutableCell<R, C, V>
|
||||
extends AbstractCell<R, C, V> implements Serializable {
|
||||
private final R rowKey;
|
||||
private final C columnKey;
|
||||
private final V value;
|
||||
|
||||
ImmutableCell(
|
||||
R rowKey, C columnKey, V value) {
|
||||
this.rowKey = rowKey;
|
||||
this.columnKey = columnKey;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public R getRowKey() {
|
||||
return rowKey;
|
||||
}
|
||||
@Override
|
||||
public C getColumnKey() {
|
||||
return columnKey;
|
||||
}
|
||||
@Override
|
||||
public V getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
abstract static class AbstractCell<R, C, V> implements Cell<R, C, V> {
|
||||
// needed for serialization
|
||||
AbstractCell() {}
|
||||
|
||||
@Override public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof Cell) {
|
||||
Cell<?, ?, ?> other = (Cell<?, ?, ?>) obj;
|
||||
return Preconditions.equal(getRowKey(), other.getRowKey())
|
||||
&& Preconditions.equal(getColumnKey(), other.getColumnKey())
|
||||
&& Preconditions.equal(getValue(), other.getValue());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
return Arrays.hashCode(new Object[] {getRowKey(), getColumnKey(), getValue()});
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "(" + getRowKey() + "," + getColumnKey() + ")=" + getValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that {@code rowKey}, {@code columnKey} and {@code value} are
|
||||
* non-null, and returns a new entry with those values.
|
||||
*/
|
||||
static <R, C, V> Cell<R, C, V> cellOf(R rowKey, C columnKey, V value) {
|
||||
return immutableCell(checkNotNull(rowKey), checkNotNull(columnKey),
|
||||
checkNotNull(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for creating immutable table instances, especially {@code public
|
||||
* static final} tables ("constant tables"). Example: <pre> {@code
|
||||
*
|
||||
* static final ImmutableTable<Integer, Character, String> SPREADSHEET =
|
||||
* new ImmutableTable.Builder<Integer, Character, String>()
|
||||
* .put(1, 'A', "foo")
|
||||
* .put(1, 'B', "bar")
|
||||
* .put(2, 'A', "baz")
|
||||
* .build();}</pre>
|
||||
*
|
||||
* <p>By default, the order in which cells are added to the builder determines
|
||||
* the iteration ordering of all views in the returned table, with {@link
|
||||
* #putAll} following the {@link Table#cellSet()} iteration order. However, if
|
||||
* {@link #orderRowsBy} or {@link #orderColumnsBy} is called, the views are
|
||||
* sorted by the supplied comparators.
|
||||
*
|
||||
* For empty or single-cell immutable tables, {@link #of()} and
|
||||
* {@link #of(Object, Object, Object)} are even more convenient.
|
||||
*
|
||||
* <p>Builder instances can be reused - it is safe to call {@link #build}
|
||||
* multiple times to build multiple tables in series. Each table is a superset
|
||||
* of the tables created before it.
|
||||
*
|
||||
* @since 11.0
|
||||
*/
|
||||
public static final class Builder<R, C, V> {
|
||||
private final List<Cell<R, C, V>> cells = Lists.newArrayList();
|
||||
private Comparator<? super R> rowComparator;
|
||||
private Comparator<? super C> columnComparator;
|
||||
|
||||
/**
|
||||
* Creates a new builder. The returned builder is equivalent to the builder
|
||||
* generated by {@link ImmutableTable#builder}.
|
||||
*/
|
||||
public Builder() {}
|
||||
|
||||
/**
|
||||
* Specifies the ordering of the generated table's rows.
|
||||
*/
|
||||
public Builder<R, C, V> orderRowsBy(Comparator<? super R> rowComparator) {
|
||||
this.rowComparator = checkNotNull(rowComparator);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the ordering of the generated table's columns.
|
||||
*/
|
||||
public Builder<R, C, V> orderColumnsBy(
|
||||
Comparator<? super C> columnComparator) {
|
||||
this.columnComparator = checkNotNull(columnComparator);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates the ({@code rowKey}, {@code columnKey}) pair with {@code
|
||||
* value} in the built table. Duplicate key pairs are not allowed and will
|
||||
* cause {@link #build} to fail.
|
||||
*/
|
||||
public Builder<R, C, V> put(R rowKey, C columnKey, V value) {
|
||||
cells.add(cellOf(rowKey, columnKey, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given {@code cell} to the table, making it immutable if
|
||||
* necessary. Duplicate key pairs are not allowed and will cause {@link
|
||||
* #build} to fail.
|
||||
*/
|
||||
public Builder<R, C, V> put(
|
||||
Cell<? extends R, ? extends C, ? extends V> cell) {
|
||||
if (cell instanceof ImmutableCell) {
|
||||
checkNotNull(cell.getRowKey());
|
||||
checkNotNull(cell.getColumnKey());
|
||||
checkNotNull(cell.getValue());
|
||||
// all supported methods are covariant
|
||||
Cell<R, C, V> immutableCell = (Cell<R, C, V>) cell;
|
||||
cells.add(immutableCell);
|
||||
} else {
|
||||
put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates all of the given table's keys and values in the built table.
|
||||
* Duplicate row key column key pairs are not allowed, and will cause
|
||||
* {@link #build} to fail.
|
||||
*
|
||||
* @throws NullPointerException if any key or value in {@code table} is null
|
||||
*/
|
||||
public Builder<R, C, V> putAll(
|
||||
Table<? extends R, ? extends C, ? extends V> table) {
|
||||
for (Cell<? extends R, ? extends C, ? extends V> cell : table.cellSet()) {
|
||||
put(cell);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a newly-created immutable table.
|
||||
*
|
||||
* @throws IllegalArgumentException if duplicate key pairs were added
|
||||
*/
|
||||
public ImmutableTable<R, C, V> build() {
|
||||
int size = cells.size();
|
||||
switch (size) {
|
||||
case 0:
|
||||
return of();
|
||||
// case 1:
|
||||
// return new SingletonImmutableTable<R, C, V>(
|
||||
// Iterables.getOnlyElement(cells));
|
||||
default:
|
||||
return RegularImmutableTable.forCells(
|
||||
cells, rowComparator, columnComparator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImmutableTable() {}
|
||||
|
||||
@Override public ImmutableSet<Cell<R, C, V>> cellSet() {
|
||||
return (ImmutableSet<Cell<R, C, V>>) super.cellSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
abstract ImmutableSet<Cell<R, C, V>> createCellSet();
|
||||
|
||||
@Override
|
||||
final UnmodifiableIterator<Cell<R, C, V>> cellIterator() {
|
||||
throw new AssertionError("should never be called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableCollection<V> values() {
|
||||
return (ImmutableCollection<V>) super.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
abstract ImmutableCollection<V> createValues();
|
||||
|
||||
@Override
|
||||
final Iterator<V> valuesIterator() {
|
||||
throw new AssertionError("should never be called");
|
||||
}
|
||||
|
||||
private static <T> T firstNonNull(T first, T second) {
|
||||
return first != null ? first : checkNotNull(second);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws NullPointerException if {@code columnKey} is {@code null}
|
||||
*/
|
||||
@Override public ImmutableMap<R, V> column(C columnKey) {
|
||||
checkNotNull(columnKey);
|
||||
return firstNonNull(
|
||||
(ImmutableMap<R, V>) columnMap().get(columnKey),
|
||||
ImmutableMap.<R, V>of());
|
||||
}
|
||||
|
||||
@Override public ImmutableSet<C> columnKeySet() {
|
||||
return columnMap().keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The value {@code Map<R, V>} instances in the returned map are
|
||||
* {@link ImmutableMap} instances as well.
|
||||
*/
|
||||
@Override public abstract ImmutableMap<C, Map<R, V>> columnMap();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws NullPointerException if {@code rowKey} is {@code null}
|
||||
*/
|
||||
@Override public ImmutableMap<C, V> row(R rowKey) {
|
||||
checkNotNull(rowKey);
|
||||
return firstNonNull(
|
||||
(ImmutableMap<C, V>) rowMap().get(rowKey),
|
||||
ImmutableMap.<C, V>of());
|
||||
}
|
||||
|
||||
@Override public ImmutableSet<R> rowKeySet() {
|
||||
return rowMap().keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The value {@code Map<C, V>} instances in the returned map are
|
||||
* {@link ImmutableMap} instances as well.
|
||||
*/
|
||||
@Override public abstract ImmutableMap<R, Map<C, V>> rowMap();
|
||||
|
||||
@Override
|
||||
public boolean contains(Object rowKey, Object columnKey) {
|
||||
return get(rowKey, columnKey) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return values().contains(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the table unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated @Override public final void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the table unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated @Override public final V put(R rowKey, C columnKey, V value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the table unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated @Override public final void putAll(
|
||||
Table<? extends R, ? extends C, ? extends V> table) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the table unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated @Override public final V remove(Object rowKey, Object columnKey) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
1029
java/src/game/collect/Iterables.java
Normal file
1029
java/src/game/collect/Iterables.java
Normal file
File diff suppressed because it is too large
Load diff
1296
java/src/game/collect/Iterators.java
Normal file
1296
java/src/game/collect/Iterators.java
Normal file
File diff suppressed because it is too large
Load diff
49
java/src/game/collect/Lists.java
Normal file
49
java/src/game/collect/Lists.java
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
||||
public final class Lists {
|
||||
public static <E> ArrayList<E> newArrayList() {
|
||||
return new ArrayList<E>();
|
||||
}
|
||||
|
||||
public static <E> ArrayList<E> newArrayList(E... elements) {
|
||||
// Avoid integer overflow when a large array is passed in
|
||||
int capacity = 5 + elements.length + (elements.length / 10);
|
||||
ArrayList<E> list = new ArrayList<E>(capacity);
|
||||
Collections.addAll(list, elements);
|
||||
return list;
|
||||
}
|
||||
|
||||
public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements) {
|
||||
// Let ArrayList's sizing logic work, if possible
|
||||
return (elements instanceof Collection)
|
||||
? new ArrayList<E>(Filter.cast(elements))
|
||||
: newArrayList(elements.iterator());
|
||||
}
|
||||
|
||||
public static <E> ArrayList<E> newArrayList(Iterator<? extends E> elements) {
|
||||
ArrayList<E> list = newArrayList();
|
||||
Iterators.addAll(list, elements);
|
||||
return list;
|
||||
}
|
||||
}
|
3953
java/src/game/collect/Maps.java
Normal file
3953
java/src/game/collect/Maps.java
Normal file
File diff suppressed because it is too large
Load diff
244
java/src/game/collect/ObjectArrays.java
Normal file
244
java/src/game/collect/ObjectArrays.java
Normal file
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Static utility methods pertaining to object arrays.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
|
||||
final class ObjectArrays {
|
||||
static final Object[] EMPTY_ARRAY = new Object[0];
|
||||
|
||||
private ObjectArrays() {}
|
||||
|
||||
/**
|
||||
* Returns a new array of the given length with the specified component type.
|
||||
*
|
||||
* @param type the component type
|
||||
* @param length the length of the new array
|
||||
*/
|
||||
//
|
||||
//
|
||||
// public static <T> T[] newArray(Class<T> type, int length) {
|
||||
// return (T[]) Array.newInstance(type, length);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns a new array of the given length with the same type as a reference
|
||||
* array.
|
||||
*
|
||||
* @param reference any array of the desired type
|
||||
* @param length the length of the new array
|
||||
*/
|
||||
public static <T> T[] newArray(T[] reference, int length) {
|
||||
// return Platform.newArray(reference, length);
|
||||
Class<?> type = reference.getClass().getComponentType();
|
||||
|
||||
// the cast is safe because
|
||||
// result.getClass() == reference.getClass().getComponentType()
|
||||
|
||||
T[] result = (T[]) Array.newInstance(type, length);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new array that contains the concatenated contents of two arrays.
|
||||
*
|
||||
* @param first the first array of elements to concatenate
|
||||
* @param second the second array of elements to concatenate
|
||||
* @param type the component type of the returned array
|
||||
*/
|
||||
//
|
||||
// public static <T> T[] concat(T[] first, T[] second, Class<T> type) {
|
||||
// T[] result = newArray(type, first.length + second.length);
|
||||
// System.arraycopy(first, 0, result, 0, first.length);
|
||||
// System.arraycopy(second, 0, result, first.length, second.length);
|
||||
// return result;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns a new array that prepends {@code element} to {@code array}.
|
||||
*
|
||||
* @param element the element to prepend to the front of {@code array}
|
||||
* @param array the array of elements to append
|
||||
* @return an array whose size is one larger than {@code array}, with
|
||||
* {@code element} occupying the first position, and the
|
||||
* elements of {@code array} occupying the remaining elements.
|
||||
*/
|
||||
// public static <T> T[] concat(T element, T[] array) {
|
||||
// T[] result = newArray(array, array.length + 1);
|
||||
// result[0] = element;
|
||||
// System.arraycopy(array, 0, result, 1, array.length);
|
||||
// return result;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns a new array that appends {@code element} to {@code array}.
|
||||
*
|
||||
* @param array the array of elements to prepend
|
||||
* @param element the element to append to the end
|
||||
* @return an array whose size is one larger than {@code array}, with
|
||||
* the same contents as {@code array}, plus {@code element} occupying the
|
||||
* last position.
|
||||
*/
|
||||
// public static <T> T[] concat(T[] array, T element) {
|
||||
// T[] result = arraysCopyOf(array, array.length + 1);
|
||||
// result[array.length] = element;
|
||||
// return result;
|
||||
// }
|
||||
|
||||
/** GWT safe version of Arrays.copyOf. */
|
||||
static <T> T[] arraysCopyOf(T[] original, int newLength) {
|
||||
T[] copy = newArray(original, newLength);
|
||||
System.arraycopy(
|
||||
original, 0, copy, 0, Math.min(original.length, newLength));
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing all of the elements in the specified
|
||||
* collection; the runtime type of the returned array is that of the specified
|
||||
* array. If the collection fits in the specified array, it is returned
|
||||
* therein. Otherwise, a new array is allocated with the runtime type of the
|
||||
* specified array and the size of the specified collection.
|
||||
*
|
||||
* <p>If the collection fits in the specified array with room to spare (i.e.,
|
||||
* the array has more elements than the collection), the element in the array
|
||||
* immediately following the end of the collection is set to {@code null}.
|
||||
* This is useful in determining the length of the collection <i>only</i> if
|
||||
* the caller knows that the collection does not contain any null elements.
|
||||
*
|
||||
* <p>This method returns the elements in the order they are returned by the
|
||||
* collection's iterator.
|
||||
*
|
||||
* <p>TODO(kevinb): support concurrently modified collections?
|
||||
*
|
||||
* @param c the collection for which to return an array of elements
|
||||
* @param array the array in which to place the collection elements
|
||||
* @throws ArrayStoreException if the runtime type of the specified array is
|
||||
* not a supertype of the runtime type of every element in the specified
|
||||
* collection
|
||||
*/
|
||||
static <T> T[] toArrayImpl(Collection<?> c, T[] array) {
|
||||
int size = c.size();
|
||||
if (array.length < size) {
|
||||
array = newArray(array, size);
|
||||
}
|
||||
fillArray(c, array);
|
||||
if (array.length > size) {
|
||||
array[size] = null;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of {@link Collection#toArray(Object[])} for collections backed by an object
|
||||
* array. the runtime type of the returned array is that of the specified array. If the collection
|
||||
* fits in the specified array, it is returned therein. Otherwise, a new array is allocated with
|
||||
* the runtime type of the specified array and the size of the specified collection.
|
||||
*
|
||||
* <p>If the collection fits in the specified array with room to spare (i.e., the array has more
|
||||
* elements than the collection), the element in the array immediately following the end of the
|
||||
* collection is set to {@code null}. This is useful in determining the length of the collection
|
||||
* <i>only</i> if the caller knows that the collection does not contain any null elements.
|
||||
*/
|
||||
// static <T> T[] toArrayImpl(Object[] src, int offset, int len, T[] dst) {
|
||||
// checkPositionIndexes(offset, offset + len, src.length);
|
||||
// if (dst.length < len) {
|
||||
// dst = newArray(dst, len);
|
||||
// } else if (dst.length > len) {
|
||||
// dst[len] = null;
|
||||
// }
|
||||
// System.arraycopy(src, offset, dst, 0, len);
|
||||
// return dst;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns an array containing all of the elements in the specified
|
||||
* collection. This method returns the elements in the order they are returned
|
||||
* by the collection's iterator. The returned array is "safe" in that no
|
||||
* references to it are maintained by the collection. The caller is thus free
|
||||
* to modify the returned array.
|
||||
*
|
||||
* <p>This method assumes that the collection size doesn't change while the
|
||||
* method is running.
|
||||
*
|
||||
* <p>TODO(kevinb): support concurrently modified collections?
|
||||
*
|
||||
* @param c the collection for which to return an array of elements
|
||||
*/
|
||||
// static Object[] toArrayImpl(Collection<?> c) {
|
||||
// return fillArray(c, new Object[c.size()]);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns a copy of the specified subrange of the specified array that is literally an Object[],
|
||||
* and not e.g. a {@code String[]}.
|
||||
*/
|
||||
// static Object[] copyAsObjectArray(Object[] elements, int offset, int length) {
|
||||
// checkPositionIndexes(offset, offset + length, elements.length);
|
||||
// if (length == 0) {
|
||||
// return EMPTY_ARRAY;
|
||||
// }
|
||||
// Object[] result = new Object[length];
|
||||
// System.arraycopy(elements, offset, result, 0, length);
|
||||
// return result;
|
||||
// }
|
||||
|
||||
private static Object[] fillArray(Iterable<?> elements, Object[] array) {
|
||||
int i = 0;
|
||||
for (Object element : elements) {
|
||||
array[i++] = element;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Swaps {@code array[i]} with {@code array[j]}.
|
||||
*/
|
||||
// static void swap(Object[] array, int i, int j) {
|
||||
// Object temp = array[i];
|
||||
// array[i] = array[j];
|
||||
// array[j] = temp;
|
||||
// }
|
||||
|
||||
static Object[] checkElementsNotNull(Object... array) {
|
||||
return checkElementsNotNull(array, array.length);
|
||||
}
|
||||
|
||||
static Object[] checkElementsNotNull(Object[] array, int length) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
checkElementNotNull(array[i], i);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
// We do this instead of Preconditions.checkNotNull to save boxing and array
|
||||
// creation cost.
|
||||
static Object checkElementNotNull(Object element, int index) {
|
||||
if (element == null) {
|
||||
throw new NullPointerException("at index " + index);
|
||||
}
|
||||
return element;
|
||||
}
|
||||
}
|
350
java/src/game/collect/Preconditions.java
Normal file
350
java/src/game/collect/Preconditions.java
Normal file
|
@ -0,0 +1,350 @@
|
|||
package game.collect;
|
||||
|
||||
final class Preconditions {
|
||||
private Preconditions() {}
|
||||
|
||||
/**
|
||||
* Ensures the truth of an expression involving one or more parameters to the calling method.
|
||||
*
|
||||
* @param expression a boolean expression
|
||||
* @throws IllegalArgumentException if {@code expression} is false
|
||||
*/
|
||||
public static void checkArgument(boolean expression) {
|
||||
if (!expression) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the truth of an expression involving one or more parameters to the calling method.
|
||||
*
|
||||
* @param expression a boolean expression
|
||||
* @param errorMessage the exception message to use if the check fails; will be converted to a
|
||||
* string using {@link String#valueOf(Object)}
|
||||
* @throws IllegalArgumentException if {@code expression} is false
|
||||
*/
|
||||
public static void checkArgument(boolean expression, Object errorMessage) {
|
||||
if (!expression) {
|
||||
throw new IllegalArgumentException(String.valueOf(errorMessage));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the truth of an expression involving one or more parameters to the calling method.
|
||||
*
|
||||
* @param expression a boolean expression
|
||||
* @param errorMessageTemplate a template for the exception message should the check fail. The
|
||||
* message is formed by replacing each {@code %s} placeholder in the template with an
|
||||
* argument. These are matched by position - the first {@code %s} gets {@code
|
||||
* errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message
|
||||
* in square braces. Unmatched placeholders will be left as-is.
|
||||
* @param errorMessageArgs the arguments to be substituted into the message template. Arguments
|
||||
* are converted to strings using {@link String#valueOf(Object)}.
|
||||
* @throws IllegalArgumentException if {@code expression} is false
|
||||
* @throws NullPointerException if the check fails and either {@code errorMessageTemplate} or
|
||||
* {@code errorMessageArgs} is null (don't let this happen)
|
||||
*/
|
||||
public static void checkArgument(boolean expression,
|
||||
String errorMessageTemplate,
|
||||
Object... errorMessageArgs) {
|
||||
if (!expression) {
|
||||
throw new IllegalArgumentException(String.format(errorMessageTemplate, errorMessageArgs));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the truth of an expression involving the state of the calling instance, but not
|
||||
* involving any parameters to the calling method.
|
||||
*
|
||||
* @param expression a boolean expression
|
||||
* @throws IllegalStateException if {@code expression} is false
|
||||
*/
|
||||
public static void checkState(boolean expression) {
|
||||
if (!expression) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the truth of an expression involving the state of the calling instance, but not
|
||||
* involving any parameters to the calling method.
|
||||
*
|
||||
* @param expression a boolean expression
|
||||
* @param errorMessage the exception message to use if the check fails; will be converted to a
|
||||
* string using {@link String#valueOf(Object)}
|
||||
* @throws IllegalStateException if {@code expression} is false
|
||||
*/
|
||||
public static void checkState(boolean expression, Object errorMessage) {
|
||||
if (!expression) {
|
||||
throw new IllegalStateException(String.valueOf(errorMessage));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the truth of an expression involving the state of the calling instance, but not
|
||||
* involving any parameters to the calling method.
|
||||
*
|
||||
* @param expression a boolean expression
|
||||
* @param errorMessageTemplate a template for the exception message should the check fail. The
|
||||
* message is formed by replacing each {@code %s} placeholder in the template with an
|
||||
* argument. These are matched by position - the first {@code %s} gets {@code
|
||||
* errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message
|
||||
* in square braces. Unmatched placeholders will be left as-is.
|
||||
* @param errorMessageArgs the arguments to be substituted into the message template. Arguments
|
||||
* are converted to strings using {@link String#valueOf(Object)}.
|
||||
* @throws IllegalStateException if {@code expression} is false
|
||||
* @throws NullPointerException if the check fails and either {@code errorMessageTemplate} or
|
||||
* {@code errorMessageArgs} is null (don't let this happen)
|
||||
*/
|
||||
// public static void checkState(boolean expression,
|
||||
// String errorMessageTemplate,
|
||||
// Object... errorMessageArgs) {
|
||||
// if (!expression) {
|
||||
// throw new IllegalStateException(String.format(errorMessageTemplate, errorMessageArgs));
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Ensures that an object reference passed as a parameter to the calling method is not null.
|
||||
*
|
||||
* @param reference an object reference
|
||||
* @return the non-null reference that was validated
|
||||
* @throws NullPointerException if {@code reference} is null
|
||||
*/
|
||||
public static <T> T checkNotNull(T reference) {
|
||||
if (reference == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
return reference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that an object reference passed as a parameter to the calling method is not null.
|
||||
*
|
||||
* @param reference an object reference
|
||||
* @param errorMessage the exception message to use if the check fails; will be converted to a
|
||||
* string using {@link String#valueOf(Object)}
|
||||
* @return the non-null reference that was validated
|
||||
* @throws NullPointerException if {@code reference} is null
|
||||
*/
|
||||
public static <T> T checkNotNull(T reference, Object errorMessage) {
|
||||
if (reference == null) {
|
||||
throw new NullPointerException(String.valueOf(errorMessage));
|
||||
}
|
||||
return reference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that an object reference passed as a parameter to the calling method is not null.
|
||||
*
|
||||
* @param reference an object reference
|
||||
* @param errorMessageTemplate a template for the exception message should the check fail. The
|
||||
* message is formed by replacing each {@code %s} placeholder in the template with an
|
||||
* argument. These are matched by position - the first {@code %s} gets {@code
|
||||
* errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message
|
||||
* in square braces. Unmatched placeholders will be left as-is.
|
||||
* @param errorMessageArgs the arguments to be substituted into the message template. Arguments
|
||||
* are converted to strings using {@link String#valueOf(Object)}.
|
||||
* @return the non-null reference that was validated
|
||||
* @throws NullPointerException if {@code reference} is null
|
||||
*/
|
||||
// public static <T> T checkNotNull(T reference,
|
||||
// String errorMessageTemplate,
|
||||
// Object... errorMessageArgs) {
|
||||
// if (reference == null) {
|
||||
// // If either of these parameters is null, the right thing happens anyway
|
||||
// throw new NullPointerException(format(errorMessageTemplate, errorMessageArgs));
|
||||
// }
|
||||
// return reference;
|
||||
// }
|
||||
|
||||
/*
|
||||
* All recent hotspots (as of 2009) *really* like to have the natural code
|
||||
*
|
||||
* if (guardExpression) {
|
||||
* throw new BadException(messageExpression);
|
||||
* }
|
||||
*
|
||||
* refactored so that messageExpression is moved to a separate String-returning method.
|
||||
*
|
||||
* if (guardExpression) {
|
||||
* throw new BadException(badMsg(...));
|
||||
* }
|
||||
*
|
||||
* The alternative natural refactorings into void or Exception-returning methods are much slower.
|
||||
* This is a big deal - we're talking factors of 2-8 in microbenchmarks, not just 10-20%. (This
|
||||
* is a hotspot optimizer bug, which should be fixed, but that's a separate, big project).
|
||||
*
|
||||
* The coding pattern above is heavily used in java.util, e.g. in ArrayList. There is a
|
||||
* RangeCheckMicroBenchmark in the JDK that was used to test this.
|
||||
*
|
||||
* But the methods in this class want to throw different exceptions, depending on the args, so it
|
||||
* appears that this pattern is not directly applicable. But we can use the ridiculous, devious
|
||||
* trick of throwing an exception in the middle of the construction of another exception. Hotspot
|
||||
* is fine with that.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Ensures that {@code index} specifies a valid <i>element</i> in an array, list or string of size
|
||||
* {@code size}. An element index may range from zero, inclusive, to {@code size}, exclusive.
|
||||
*
|
||||
* @param index a user-supplied index identifying an element of an array, list or string
|
||||
* @param size the size of that array, list or string
|
||||
* @return the value of {@code index}
|
||||
* @throws IndexOutOfBoundsException if {@code index} is negative or is not less than {@code size}
|
||||
* @throws IllegalArgumentException if {@code size} is negative
|
||||
*/
|
||||
// public static int checkElementIndex(int index, int size) {
|
||||
// return checkElementIndex(index, size, "index");
|
||||
// }
|
||||
|
||||
/**
|
||||
* Ensures that {@code index} specifies a valid <i>element</i> in an array, list or string of size
|
||||
* {@code size}. An element index may range from zero, inclusive, to {@code size}, exclusive.
|
||||
*
|
||||
* @param index a user-supplied index identifying an element of an array, list or string
|
||||
* @param size the size of that array, list or string
|
||||
* @param desc the text to use to describe this index in an error message
|
||||
* @return the value of {@code index}
|
||||
* @throws IndexOutOfBoundsException if {@code index} is negative or is not less than {@code size}
|
||||
* @throws IllegalArgumentException if {@code size} is negative
|
||||
*/
|
||||
public static int checkElementIndex(
|
||||
int index, int size) {
|
||||
// Carefully optimized for execution by hotspot (explanatory comment above)
|
||||
if (index < 0 || index >= size) {
|
||||
throw new IndexOutOfBoundsException(badElementIndex(index, size));
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
private static String badElementIndex(int index, int size) {
|
||||
if (index < 0) {
|
||||
return String.format("index (%d) must not be negative", index);
|
||||
} else if (size < 0) {
|
||||
throw new IllegalArgumentException("negative size: " + size);
|
||||
} else { // index >= size
|
||||
return String.format("index (%d) must be less than size (%d)", index, size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that {@code index} specifies a valid <i>position</i> in an array, list or string of
|
||||
* size {@code size}. A position index may range from zero to {@code size}, inclusive.
|
||||
*
|
||||
* @param index a user-supplied index identifying a position in an array, list or string
|
||||
* @param size the size of that array, list or string
|
||||
* @return the value of {@code index}
|
||||
* @throws IndexOutOfBoundsException if {@code index} is negative or is greater than {@code size}
|
||||
* @throws IllegalArgumentException if {@code size} is negative
|
||||
*/
|
||||
// public static int checkPositionIndex(int index, int size) {
|
||||
// return checkPositionIndex(index, size, "index");
|
||||
// }
|
||||
|
||||
/**
|
||||
* Ensures that {@code index} specifies a valid <i>position</i> in an array, list or string of
|
||||
* size {@code size}. A position index may range from zero to {@code size}, inclusive.
|
||||
*
|
||||
* @param index a user-supplied index identifying a position in an array, list or string
|
||||
* @param size the size of that array, list or string
|
||||
* @param desc the text to use to describe this index in an error message
|
||||
* @return the value of {@code index}
|
||||
* @throws IndexOutOfBoundsException if {@code index} is negative or is greater than {@code size}
|
||||
* @throws IllegalArgumentException if {@code size} is negative
|
||||
*/
|
||||
public static int checkPositionIndex(int index, int size) {
|
||||
// Carefully optimized for execution by hotspot (explanatory comment above)
|
||||
if (index < 0 || index > size) {
|
||||
throw new IndexOutOfBoundsException(badPositionIndex(index, size, "index"));
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
private static String badPositionIndex(int index, int size, String desc) {
|
||||
if (index < 0) {
|
||||
return String.format("%s (%d) must not be negative", desc, index);
|
||||
} else if (size < 0) {
|
||||
throw new IllegalArgumentException("negative size: " + size);
|
||||
} else { // index > size
|
||||
return String.format("%s (%d) must not be greater than size (%s)", desc, index, size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that {@code start} and {@code end} specify a valid <i>positions</i> in an array, list
|
||||
* or string of size {@code size}, and are in order. A position index may range from zero to
|
||||
* {@code size}, inclusive.
|
||||
*
|
||||
* @param start a user-supplied index identifying a starting position in an array, list or string
|
||||
* @param end a user-supplied index identifying a ending position in an array, list or string
|
||||
* @param size the size of that array, list or string
|
||||
* @throws IndexOutOfBoundsException if either index is negative or is greater than {@code size},
|
||||
* or if {@code end} is less than {@code start}
|
||||
* @throws IllegalArgumentException if {@code size} is negative
|
||||
*/
|
||||
public static void checkPositionIndexes(int start, int end, int size) {
|
||||
// Carefully optimized for execution by hotspot (explanatory comment above)
|
||||
if (start < 0 || end < start || end > size) {
|
||||
throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size));
|
||||
}
|
||||
}
|
||||
|
||||
private static String badPositionIndexes(int start, int end, int size) {
|
||||
if (start < 0 || start > size) {
|
||||
return badPositionIndex(start, size, "start index");
|
||||
}
|
||||
if (end < 0 || end > size) {
|
||||
return badPositionIndex(end, size, "end index");
|
||||
}
|
||||
// end < start
|
||||
return String.format("end index (%d) must not be less than start index (%d)", end, start);
|
||||
}
|
||||
|
||||
public static boolean equal(Object a, Object b) {
|
||||
return a == b || (a != null && a.equals(b));
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes each {@code %s} in {@code template} with an argument. These are matched by
|
||||
* position: the first {@code %s} gets {@code args[0]}, etc. If there are more arguments than
|
||||
* placeholders, the unmatched arguments will be appended to the end of the formatted message in
|
||||
* square braces.
|
||||
*
|
||||
* @param template a non-null string containing 0 or more {@code %s} placeholders.
|
||||
* @param args the arguments to be substituted into the message template. Arguments are converted
|
||||
* to strings using {@link String#valueOf(Object)}. Arguments can be null.
|
||||
*/
|
||||
// // Note that this is somewhat-improperly used from Verify.java as well.
|
||||
// static String format(String template, Object... args) {
|
||||
// template = String.valueOf(template); // null -> "null"
|
||||
//
|
||||
// // start substituting the arguments into the '%s' placeholders
|
||||
// StringBuilder builder = new StringBuilder(template.length() + 16 * args.length);
|
||||
// int templateStart = 0;
|
||||
// int i = 0;
|
||||
// while (i < args.length) {
|
||||
// int placeholderStart = template.indexOf("%s", templateStart);
|
||||
// if (placeholderStart == -1) {
|
||||
// break;
|
||||
// }
|
||||
// builder.append(template.substring(templateStart, placeholderStart));
|
||||
// builder.append(args[i++]);
|
||||
// templateStart = placeholderStart + 2;
|
||||
// }
|
||||
// builder.append(template.substring(templateStart));
|
||||
//
|
||||
// // if we run out of placeholders, append the extra args in square braces
|
||||
// if (i < args.length) {
|
||||
// builder.append(" [");
|
||||
// builder.append(args[i++]);
|
||||
// while (i < args.length) {
|
||||
// builder.append(", ");
|
||||
// builder.append(args[i++]);
|
||||
// }
|
||||
// builder.append(']');
|
||||
// }
|
||||
//
|
||||
// return builder.toString();
|
||||
// }
|
||||
}
|
65
java/src/game/collect/RegularImmutableAsList.java
Normal file
65
java/src/game/collect/RegularImmutableAsList.java
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (C) 2012 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
/**
|
||||
* An {@link ImmutableAsList} implementation specialized for when the delegate collection is
|
||||
* already backed by an {@code ImmutableList} or array.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
|
||||
// uses writeReplace, not default serialization
|
||||
class RegularImmutableAsList<E> extends ImmutableAsList<E> {
|
||||
private final ImmutableCollection<E> delegate;
|
||||
private final ImmutableList<? extends E> delegateList;
|
||||
|
||||
RegularImmutableAsList(ImmutableCollection<E> delegate, ImmutableList<? extends E> delegateList) {
|
||||
this.delegate = delegate;
|
||||
this.delegateList = delegateList;
|
||||
}
|
||||
|
||||
RegularImmutableAsList(ImmutableCollection<E> delegate, Object[] array) {
|
||||
this(delegate, ImmutableList.<E>asImmutableList(array));
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableCollection<E> delegateCollection() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
ImmutableList<? extends E> delegateList() {
|
||||
return delegateList;
|
||||
}
|
||||
|
||||
// safe covariant cast!
|
||||
@Override
|
||||
public UnmodifiableListIterator<E> listIterator(int index) {
|
||||
return (UnmodifiableListIterator<E>) delegateList.listIterator(index);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
int copyIntoArray(Object[] dst, int offset) {
|
||||
return delegateList.copyIntoArray(dst, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int index) {
|
||||
return delegateList.get(index);
|
||||
}
|
||||
}
|
106
java/src/game/collect/RegularImmutableList.java
Normal file
106
java/src/game/collect/RegularImmutableList.java
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (C) 2009 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ImmutableList} with one or more elements.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
*/
|
||||
|
||||
// uses writeReplace(), not default serialization
|
||||
class RegularImmutableList<E> extends ImmutableList<E> {
|
||||
private final transient int offset;
|
||||
private final transient int size;
|
||||
private final transient Object[] array;
|
||||
|
||||
RegularImmutableList(Object[] array, int offset, int size) {
|
||||
this.offset = offset;
|
||||
this.size = size;
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
RegularImmutableList(Object[] array) {
|
||||
this(array, 0, array.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override boolean isPartialView() {
|
||||
return size != array.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
int copyIntoArray(Object[] dst, int dstOff) {
|
||||
System.arraycopy(array, offset, dst, dstOff, size);
|
||||
return dstOff + size;
|
||||
}
|
||||
|
||||
// The fake cast to E is safe because the creation methods only allow E's
|
||||
@Override
|
||||
|
||||
public E get(int index) {
|
||||
Preconditions.checkElementIndex(index, size);
|
||||
return (E) array[index + offset];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object object) {
|
||||
if (object == null) {
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (array[offset + i].equals(object)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf(Object object) {
|
||||
if (object == null) {
|
||||
return -1;
|
||||
}
|
||||
for (int i = size - 1; i >= 0; i--) {
|
||||
if (array[offset + i].equals(object)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableList<E> subListUnchecked(int fromIndex, int toIndex) {
|
||||
return new RegularImmutableList<E>(
|
||||
array, offset + fromIndex, toIndex - fromIndex);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public UnmodifiableListIterator<E> listIterator(int index) {
|
||||
// for performance
|
||||
// The fake cast to E is safe because the creation methods only allow E's
|
||||
return (UnmodifiableListIterator<E>)
|
||||
Iterators.forArray(array, offset, size, index);
|
||||
}
|
||||
|
||||
// TODO(user): benchmark optimizations for equals() and see if they're worthwhile
|
||||
}
|
205
java/src/game/collect/RegularImmutableMap.java
Normal file
205
java/src/game/collect/RegularImmutableMap.java
Normal file
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.CollectPreconditions.checkEntryNotNull;
|
||||
|
||||
import game.collect.ImmutableMapEntry.TerminalEntry;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ImmutableMap} with two or more entries.
|
||||
*
|
||||
* @author Jesse Wilson
|
||||
* @author Kevin Bourrillion
|
||||
* @author Gregory Kick
|
||||
*/
|
||||
|
||||
final class RegularImmutableMap<K, V> extends ImmutableMap<K, V> {
|
||||
|
||||
// entries in insertion order
|
||||
private final transient ImmutableMapEntry<K, V>[] entries;
|
||||
// array of linked lists of entries
|
||||
private final transient ImmutableMapEntry<K, V>[] table;
|
||||
// 'and' with an int to get a table index
|
||||
private final transient int mask;
|
||||
|
||||
RegularImmutableMap(TerminalEntry<?, ?>... theEntries) {
|
||||
this(theEntries.length, theEntries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for RegularImmutableMap that takes as input an array of {@code TerminalEntry}
|
||||
* entries. Assumes that these entries have already been checked for null.
|
||||
*
|
||||
* <p>This allows reuse of the entry objects from the array in the actual implementation.
|
||||
*/
|
||||
RegularImmutableMap(int size, TerminalEntry<?, ?>[] theEntries) {
|
||||
entries = createEntryArray(size);
|
||||
int tableSize = Hashing.closedTableSize(size, MAX_LOAD_FACTOR);
|
||||
table = createEntryArray(tableSize);
|
||||
mask = tableSize - 1;
|
||||
for (int entryIndex = 0; entryIndex < size; entryIndex++) {
|
||||
|
||||
TerminalEntry<K, V> entry = (TerminalEntry<K, V>) theEntries[entryIndex];
|
||||
K key = entry.getKey();
|
||||
int tableIndex = Hashing.smear(key.hashCode()) & mask;
|
||||
ImmutableMapEntry<K, V> existing = table[tableIndex];
|
||||
// prepend, not append, so the entries can be immutable
|
||||
ImmutableMapEntry<K, V> newEntry = (existing == null)
|
||||
? entry
|
||||
: new NonTerminalMapEntry<K, V>(entry, existing);
|
||||
table[tableIndex] = newEntry;
|
||||
entries[entryIndex] = newEntry;
|
||||
checkNoConflictInBucket(key, newEntry, existing);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for RegularImmutableMap that makes no assumptions about the input entries.
|
||||
*/
|
||||
RegularImmutableMap(Entry<?, ?>[] theEntries) {
|
||||
int size = theEntries.length;
|
||||
entries = createEntryArray(size);
|
||||
int tableSize = Hashing.closedTableSize(size, MAX_LOAD_FACTOR);
|
||||
table = createEntryArray(tableSize);
|
||||
mask = tableSize - 1;
|
||||
for (int entryIndex = 0; entryIndex < size; entryIndex++) {
|
||||
// all our callers carefully put in only Entry<K, V>s
|
||||
Entry<K, V> entry = (Entry<K, V>) theEntries[entryIndex];
|
||||
K key = entry.getKey();
|
||||
V value = entry.getValue();
|
||||
checkEntryNotNull(key, value);
|
||||
int tableIndex = Hashing.smear(key.hashCode()) & mask;
|
||||
ImmutableMapEntry<K, V> existing = table[tableIndex];
|
||||
// prepend, not append, so the entries can be immutable
|
||||
ImmutableMapEntry<K, V> newEntry = (existing == null)
|
||||
? new TerminalEntry<K, V>(key, value)
|
||||
: new NonTerminalMapEntry<K, V>(key, value, existing);
|
||||
table[tableIndex] = newEntry;
|
||||
entries[entryIndex] = newEntry;
|
||||
checkNoConflictInBucket(key, newEntry, existing);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkNoConflictInBucket(
|
||||
K key, ImmutableMapEntry<K, V> entry, ImmutableMapEntry<K, V> bucketHead) {
|
||||
for (; bucketHead != null; bucketHead = bucketHead.getNextInKeyBucket()) {
|
||||
checkNoConflict(!key.equals(bucketHead.getKey()), "key", entry, bucketHead);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class NonTerminalMapEntry<K, V> extends ImmutableMapEntry<K, V> {
|
||||
private final ImmutableMapEntry<K, V> nextInKeyBucket;
|
||||
|
||||
NonTerminalMapEntry(K key, V value, ImmutableMapEntry<K, V> nextInKeyBucket) {
|
||||
super(key, value);
|
||||
this.nextInKeyBucket = nextInKeyBucket;
|
||||
}
|
||||
|
||||
NonTerminalMapEntry(ImmutableMapEntry<K, V> contents, ImmutableMapEntry<K, V> nextInKeyBucket) {
|
||||
super(contents);
|
||||
this.nextInKeyBucket = nextInKeyBucket;
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableMapEntry<K, V> getNextInKeyBucket() {
|
||||
return nextInKeyBucket;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
ImmutableMapEntry<K, V> getNextInValueBucket() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Closed addressing tends to perform well even with high load factors.
|
||||
* Being conservative here ensures that the table is still likely to be
|
||||
* relatively sparse (hence it misses fast) while saving space.
|
||||
*/
|
||||
private static final double MAX_LOAD_FACTOR = 1.2;
|
||||
|
||||
/**
|
||||
* Creates an {@code ImmutableMapEntry} array to hold parameterized entries. The
|
||||
* result must never be upcast back to ImmutableMapEntry[] (or Object[], etc.), or
|
||||
* allowed to escape the class.
|
||||
*/
|
||||
// Safe as long as the javadocs are followed
|
||||
private ImmutableMapEntry<K, V>[] createEntryArray(int size) {
|
||||
return new ImmutableMapEntry[size];
|
||||
}
|
||||
|
||||
@Override public V get(Object key) {
|
||||
if (key == null) {
|
||||
return null;
|
||||
}
|
||||
int index = Hashing.smear(key.hashCode()) & mask;
|
||||
for (ImmutableMapEntry<K, V> entry = table[index];
|
||||
entry != null;
|
||||
entry = entry.getNextInKeyBucket()) {
|
||||
K candidateKey = entry.getKey();
|
||||
|
||||
/*
|
||||
* Assume that equals uses the == optimization when appropriate, and that
|
||||
* it would check hash codes as an optimization when appropriate. If we
|
||||
* did these things, it would just make things worse for the most
|
||||
* performance-conscious users.
|
||||
*/
|
||||
if (key.equals(candidateKey)) {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return entries.length;
|
||||
}
|
||||
|
||||
@Override boolean isPartialView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableSet<Entry<K, V>> createEntrySet() {
|
||||
return new EntrySet();
|
||||
}
|
||||
|
||||
// uses writeReplace(), not default serialization
|
||||
private class EntrySet extends ImmutableMapEntrySet<K, V> {
|
||||
@Override ImmutableMap<K, V> map() {
|
||||
return RegularImmutableMap.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnmodifiableIterator<Entry<K, V>> iterator() {
|
||||
return asList().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableList<Entry<K, V>> createAsList() {
|
||||
return new RegularImmutableAsList<Entry<K, V>>(this, entries);
|
||||
}
|
||||
}
|
||||
|
||||
// This class is never actually serialized directly, but we have to make the
|
||||
// warning go away (and suppressing would suppress for all nested classes too)
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
92
java/src/game/collect/RegularImmutableSet.java
Normal file
92
java/src/game/collect/RegularImmutableSet.java
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ImmutableSet} with two or more elements.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
*/
|
||||
|
||||
// uses writeReplace(), not default serialization
|
||||
final class RegularImmutableSet<E> extends ImmutableSet<E> {
|
||||
private final Object[] elements;
|
||||
// the same elements in hashed positions (plus nulls)
|
||||
// @VisibleForTesting
|
||||
final transient Object[] table;
|
||||
// 'and' with an int to get a valid table index.
|
||||
private final transient int mask;
|
||||
private final transient int hashCode;
|
||||
|
||||
RegularImmutableSet(
|
||||
Object[] elements, int hashCode, Object[] table, int mask) {
|
||||
this.elements = elements;
|
||||
this.table = table;
|
||||
this.mask = mask;
|
||||
this.hashCode = hashCode;
|
||||
}
|
||||
|
||||
@Override public boolean contains(Object target) {
|
||||
if (target == null) {
|
||||
return false;
|
||||
}
|
||||
for (int i = Hashing.smear(target.hashCode()); true; i++) {
|
||||
Object candidate = table[i & mask];
|
||||
if (candidate == null) {
|
||||
return false;
|
||||
}
|
||||
if (candidate.equals(target)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return elements.length;
|
||||
}
|
||||
|
||||
// all elements are E's
|
||||
@Override
|
||||
public UnmodifiableIterator<E> iterator() {
|
||||
return (UnmodifiableIterator<E>) Iterators.forArray(elements);
|
||||
}
|
||||
|
||||
@Override
|
||||
int copyIntoArray(Object[] dst, int offset) {
|
||||
System.arraycopy(elements, 0, dst, offset, elements.length);
|
||||
return offset + elements.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableList<E> createAsList() {
|
||||
return new RegularImmutableAsList<E>(this, elements);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override boolean isHashCodeFast() {
|
||||
return true;
|
||||
}
|
||||
}
|
175
java/src/game/collect/RegularImmutableTable.java
Normal file
175
java/src/game/collect/RegularImmutableTable.java
Normal file
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Copyright (C) 2009 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An implementation of {@link ImmutableTable} holding an arbitrary number of
|
||||
* cells.
|
||||
*
|
||||
* @author Gregory Kick
|
||||
*/
|
||||
|
||||
abstract class RegularImmutableTable<R, C, V> extends ImmutableTable<R, C, V> {
|
||||
RegularImmutableTable() {}
|
||||
|
||||
abstract Cell<R, C, V> getCell(int iterationIndex);
|
||||
|
||||
@Override
|
||||
final ImmutableSet<Cell<R, C, V>> createCellSet() {
|
||||
return isEmpty() ? ImmutableSet.<Cell<R, C, V>>of() : new CellSet();
|
||||
}
|
||||
|
||||
private final class CellSet extends ImmutableSet<Cell<R, C, V>> {
|
||||
@Override
|
||||
public int size() {
|
||||
return RegularImmutableTable.this.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnmodifiableIterator<Cell<R, C, V>> iterator() {
|
||||
return asList().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableList<Cell<R, C, V>> createAsList() {
|
||||
return new ImmutableAsList<Cell<R, C, V>>() {
|
||||
@Override
|
||||
public Cell<R, C, V> get(int index) {
|
||||
return getCell(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableCollection<Cell<R, C, V>> delegateCollection() {
|
||||
return CellSet.this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object object) {
|
||||
if (object instanceof Cell) {
|
||||
Cell<?, ?, ?> cell = (Cell<?, ?, ?>) object;
|
||||
Object value = get(cell.getRowKey(), cell.getColumnKey());
|
||||
return value != null && value.equals(cell.getValue());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
abstract V getValue(int iterationIndex);
|
||||
|
||||
@Override
|
||||
final ImmutableCollection<V> createValues() {
|
||||
return isEmpty() ? ImmutableList.<V>of() : new Values();
|
||||
}
|
||||
|
||||
private final class Values extends ImmutableList<V> {
|
||||
@Override
|
||||
public int size() {
|
||||
return RegularImmutableTable.this.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(int index) {
|
||||
return getValue(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static <R, C, V> RegularImmutableTable<R, C, V> forCells(
|
||||
List<Cell<R, C, V>> cells,
|
||||
final Comparator<? super R> rowComparator,
|
||||
final Comparator<? super C> columnComparator) {
|
||||
checkNotNull(cells);
|
||||
if (rowComparator != null || columnComparator != null) {
|
||||
/*
|
||||
* This sorting logic leads to a cellSet() ordering that may not be expected and that isn't
|
||||
* documented in the Javadoc. If a row Comparator is provided, cellSet() iterates across the
|
||||
* columns in the first row, the columns in the second row, etc. If a column Comparator is
|
||||
* provided but a row Comparator isn't, cellSet() iterates across the rows in the first
|
||||
* column, the rows in the second column, etc.
|
||||
*/
|
||||
Comparator<Cell<R, C, V>> comparator = new Comparator<Cell<R, C, V>>() {
|
||||
@Override public int compare(Cell<R, C, V> cell1, Cell<R, C, V> cell2) {
|
||||
int rowCompare = (rowComparator == null) ? 0
|
||||
: rowComparator.compare(cell1.getRowKey(), cell2.getRowKey());
|
||||
if (rowCompare != 0) {
|
||||
return rowCompare;
|
||||
}
|
||||
return (columnComparator == null) ? 0
|
||||
: columnComparator.compare(cell1.getColumnKey(), cell2.getColumnKey());
|
||||
}
|
||||
};
|
||||
Collections.sort(cells, comparator);
|
||||
}
|
||||
return forCellsInternal(cells, rowComparator, columnComparator);
|
||||
}
|
||||
|
||||
static <R, C, V> RegularImmutableTable<R, C, V> forCells(
|
||||
Iterable<Cell<R, C, V>> cells) {
|
||||
return forCellsInternal(cells, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* A factory that chooses the most space-efficient representation of the
|
||||
* table.
|
||||
*/
|
||||
private static final <R, C, V> RegularImmutableTable<R, C, V>
|
||||
forCellsInternal(Iterable<Cell<R, C, V>> cells,
|
||||
Comparator<? super R> rowComparator,
|
||||
Comparator<? super C> columnComparator) {
|
||||
ImmutableSet.Builder<R> rowSpaceBuilder = ImmutableSet.builder();
|
||||
ImmutableSet.Builder<C> columnSpaceBuilder = ImmutableSet.builder();
|
||||
ImmutableList<Cell<R, C, V>> cellList = ImmutableList.copyOf(cells);
|
||||
for (Cell<R, C, V> cell : cellList) {
|
||||
rowSpaceBuilder.add(cell.getRowKey());
|
||||
columnSpaceBuilder.add(cell.getColumnKey());
|
||||
}
|
||||
|
||||
ImmutableSet<R> rowSpace = rowSpaceBuilder.build();
|
||||
if (rowComparator != null) {
|
||||
List<R> rowList = Lists.newArrayList(rowSpace);
|
||||
Collections.sort(rowList, rowComparator);
|
||||
rowSpace = ImmutableSet.copyOf(rowList);
|
||||
}
|
||||
ImmutableSet<C> columnSpace = columnSpaceBuilder.build();
|
||||
if (columnComparator != null) {
|
||||
List<C> columnList = Lists.newArrayList(columnSpace);
|
||||
Collections.sort(columnList, columnComparator);
|
||||
columnSpace = ImmutableSet.copyOf(columnList);
|
||||
}
|
||||
|
||||
// use a dense table if more than half of the cells have values
|
||||
// TODO(gak): tune this condition based on empirical evidence
|
||||
return (cellList.size() > (((long) rowSpace.size() * columnSpace.size()) / 2)) ?
|
||||
new DenseImmutableTable<R, C, V>(cellList, rowSpace, columnSpace) :
|
||||
new SparseImmutableTable<R, C, V>(cellList, rowSpace, columnSpace);
|
||||
}
|
||||
}
|
1607
java/src/game/collect/Sets.java
Normal file
1607
java/src/game/collect/Sets.java
Normal file
File diff suppressed because it is too large
Load diff
108
java/src/game/collect/SparseImmutableTable.java
Normal file
108
java/src/game/collect/SparseImmutableTable.java
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (C) 2009 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A {@code RegularImmutableTable} optimized for sparse data.
|
||||
*/
|
||||
|
||||
//@Immutable
|
||||
final class SparseImmutableTable<R, C, V>
|
||||
extends RegularImmutableTable<R, C, V> {
|
||||
|
||||
private final ImmutableMap<R, Map<C, V>> rowMap;
|
||||
private final ImmutableMap<C, Map<R, V>> columnMap;
|
||||
private final int[] iterationOrderRow;
|
||||
private final int[] iterationOrderColumn;
|
||||
|
||||
SparseImmutableTable(ImmutableList<Cell<R, C, V>> cellList,
|
||||
ImmutableSet<R> rowSpace, ImmutableSet<C> columnSpace) {
|
||||
Map<R, Integer> rowIndex = Maps.newHashMap();
|
||||
Map<R, Map<C, V>> rows = Maps.newLinkedHashMap();
|
||||
for (R row : rowSpace) {
|
||||
rowIndex.put(row, rows.size());
|
||||
rows.put(row, new LinkedHashMap<C, V>());
|
||||
}
|
||||
Map<C, Map<R, V>> columns = Maps.newLinkedHashMap();
|
||||
for (C col : columnSpace) {
|
||||
columns.put(col, new LinkedHashMap<R, V>());
|
||||
}
|
||||
int[] iterationOrderRow = new int[cellList.size()];
|
||||
int[] iterationOrderColumn = new int[cellList.size()];
|
||||
for (int i = 0; i < cellList.size(); i++) {
|
||||
Cell<R, C, V> cell = cellList.get(i);
|
||||
R rowKey = cell.getRowKey();
|
||||
C columnKey = cell.getColumnKey();
|
||||
V value = cell.getValue();
|
||||
|
||||
iterationOrderRow[i] = rowIndex.get(rowKey);
|
||||
Map<C, V> thisRow = rows.get(rowKey);
|
||||
iterationOrderColumn[i] = thisRow.size();
|
||||
V oldValue = thisRow.put(columnKey, value);
|
||||
if (oldValue != null) {
|
||||
throw new IllegalArgumentException("Duplicate value for row=" + rowKey + ", column="
|
||||
+ columnKey + ": " + value + ", " + oldValue);
|
||||
}
|
||||
columns.get(columnKey).put(rowKey, value);
|
||||
}
|
||||
this.iterationOrderRow = iterationOrderRow;
|
||||
this.iterationOrderColumn = iterationOrderColumn;
|
||||
ImmutableMap.Builder<R, Map<C, V>> rowBuilder = ImmutableMap.builder();
|
||||
for (Map.Entry<R, Map<C, V>> row : rows.entrySet()) {
|
||||
rowBuilder.put(row.getKey(), ImmutableMap.copyOf(row.getValue()));
|
||||
}
|
||||
this.rowMap = rowBuilder.build();
|
||||
|
||||
ImmutableMap.Builder<C, Map<R, V>> columnBuilder = ImmutableMap.builder();
|
||||
for (Map.Entry<C, Map<R, V>> col : columns.entrySet()) {
|
||||
columnBuilder.put(col.getKey(), ImmutableMap.copyOf(col.getValue()));
|
||||
}
|
||||
this.columnMap = columnBuilder.build();
|
||||
}
|
||||
|
||||
@Override public ImmutableMap<C, Map<R, V>> columnMap() {
|
||||
return columnMap;
|
||||
}
|
||||
|
||||
@Override public ImmutableMap<R, Map<C, V>> rowMap() {
|
||||
return rowMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return iterationOrderRow.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
Cell<R, C, V> getCell(int index) {
|
||||
int rowIndex = iterationOrderRow[index];
|
||||
Map.Entry<R, Map<C, V>> rowEntry = rowMap.entrySet().asList().get(rowIndex);
|
||||
ImmutableMap<C, V> row = (ImmutableMap<C, V>) rowEntry.getValue();
|
||||
int columnIndex = iterationOrderColumn[index];
|
||||
Map.Entry<C, V> colEntry = row.entrySet().asList().get(columnIndex);
|
||||
return cellOf(rowEntry.getKey(), colEntry.getKey(), colEntry.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
V getValue(int index) {
|
||||
int rowIndex = iterationOrderRow[index];
|
||||
ImmutableMap<C, V> row = (ImmutableMap<C, V>) rowMap.values().asList().get(rowIndex);
|
||||
int columnIndex = iterationOrderColumn[index];
|
||||
return row.values().asList().get(columnIndex);
|
||||
}
|
||||
}
|
891
java/src/game/collect/StandardTable.java
Normal file
891
java/src/game/collect/StandardTable.java
Normal file
|
@ -0,0 +1,891 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.Maps.safeContainsKey;
|
||||
import static game.collect.Maps.safeGet;
|
||||
import static game.collect.Preconditions.checkNotNull;
|
||||
import static game.util.Predicates.alwaysTrue;
|
||||
import static game.util.Predicates.equalTo;
|
||||
import static game.util.Predicates.in;
|
||||
import static game.util.Predicates.not;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import game.collect.Maps.ImprovedAbstractMap;
|
||||
import game.collect.Sets.ImprovedAbstractSet;
|
||||
|
||||
/**
|
||||
* {@link Table} implementation backed by a map that associates row keys with
|
||||
* column key / value secondary maps. This class provides rapid access to
|
||||
* records by the row key alone or by both keys, but not by just the column key.
|
||||
*
|
||||
* <p>The views returned by {@link #column}, {@link #columnKeySet()}, and {@link
|
||||
* #columnMap()} have iterators that don't support {@code remove()}. Otherwise,
|
||||
* all optional operations are supported. Null row keys, columns keys, and
|
||||
* values are not supported.
|
||||
*
|
||||
* <p>Lookups by row key are often faster than lookups by column key, because
|
||||
* the data is stored in a {@code Map<R, Map<C, V>>}. A method call like {@code
|
||||
* column(columnKey).get(rowKey)} still runs quickly, since the row key is
|
||||
* provided. However, {@code column(columnKey).size()} takes longer, since an
|
||||
* iteration across all row keys occurs.
|
||||
*
|
||||
* <p>Note that this implementation is not synchronized. If multiple threads
|
||||
* access this table concurrently and one of the threads modifies the table, it
|
||||
* must be synchronized externally.
|
||||
*
|
||||
* @author Jared Levy
|
||||
*/
|
||||
|
||||
public class StandardTable<R, C, V> extends AbstractTable<R, C, V> implements Serializable {
|
||||
final Map<R, Map<C, V>> backingMap = new HashMap<R, Map<C, V>>();
|
||||
// final Supplier<? extends Map<C, V>> factory;
|
||||
|
||||
// StandardTable(Map<R, Map<C, V>> backingMap) {
|
||||
// this.backingMap = backingMap;
|
||||
//// this.factory = factory;
|
||||
// }
|
||||
|
||||
// Accessors
|
||||
|
||||
@Override public boolean contains(
|
||||
Object rowKey, Object columnKey) {
|
||||
return rowKey != null && columnKey != null && super.contains(rowKey, columnKey);
|
||||
}
|
||||
|
||||
@Override public boolean containsColumn(Object columnKey) {
|
||||
if (columnKey == null) {
|
||||
return false;
|
||||
}
|
||||
for (Map<C, V> map : backingMap.values()) {
|
||||
if (safeContainsKey(map, columnKey)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean containsRow(Object rowKey) {
|
||||
return rowKey != null && safeContainsKey(backingMap, rowKey);
|
||||
}
|
||||
|
||||
@Override public boolean containsValue(Object value) {
|
||||
return value != null && super.containsValue(value);
|
||||
}
|
||||
|
||||
@Override public V get(Object rowKey, Object columnKey) {
|
||||
return (rowKey == null || columnKey == null)
|
||||
? null
|
||||
: super.get(rowKey, columnKey);
|
||||
}
|
||||
|
||||
@Override public boolean isEmpty() {
|
||||
return backingMap.isEmpty();
|
||||
}
|
||||
|
||||
@Override public int size() {
|
||||
int size = 0;
|
||||
for (Map<C, V> map : backingMap.values()) {
|
||||
size += map.size();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
// Mutators
|
||||
|
||||
@Override public void clear() {
|
||||
backingMap.clear();
|
||||
}
|
||||
|
||||
private Map<C, V> getOrCreate(R rowKey) {
|
||||
Map<C, V> map = backingMap.get(rowKey);
|
||||
if (map == null) {
|
||||
map = Maps.newHashMapWithExpectedSize(0);
|
||||
// map = factory.get();
|
||||
backingMap.put(rowKey, map);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override public V put(R rowKey, C columnKey, V value) {
|
||||
checkNotNull(rowKey);
|
||||
checkNotNull(columnKey);
|
||||
checkNotNull(value);
|
||||
return getOrCreate(rowKey).put(columnKey, value);
|
||||
}
|
||||
|
||||
@Override public V remove(
|
||||
Object rowKey, Object columnKey) {
|
||||
if ((rowKey == null) || (columnKey == null)) {
|
||||
return null;
|
||||
}
|
||||
Map<C, V> map = safeGet(backingMap, rowKey);
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
V value = map.remove(columnKey);
|
||||
if (map.isEmpty()) {
|
||||
backingMap.remove(rowKey);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private Map<R, V> removeColumn(Object column) {
|
||||
Map<R, V> output = new LinkedHashMap<R, V>();
|
||||
Iterator<Entry<R, Map<C, V>>> iterator
|
||||
= backingMap.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Entry<R, Map<C, V>> entry = iterator.next();
|
||||
V value = entry.getValue().remove(column);
|
||||
if (value != null) {
|
||||
output.put(entry.getKey(), value);
|
||||
if (entry.getValue().isEmpty()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
private boolean containsMapping(
|
||||
Object rowKey, Object columnKey, Object value) {
|
||||
return value != null && value.equals(get(rowKey, columnKey));
|
||||
}
|
||||
|
||||
/** Remove a row key / column key / value mapping, if present. */
|
||||
private boolean removeMapping(Object rowKey, Object columnKey, Object value) {
|
||||
if (containsMapping(rowKey, columnKey, value)) {
|
||||
remove(rowKey, columnKey);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Views
|
||||
|
||||
/**
|
||||
* Abstract set whose {@code isEmpty()} returns whether the table is empty and
|
||||
* whose {@code clear()} clears all table mappings.
|
||||
*/
|
||||
private abstract class TableSet<T> extends ImprovedAbstractSet<T> {
|
||||
@Override public boolean isEmpty() {
|
||||
return backingMap.isEmpty();
|
||||
}
|
||||
|
||||
@Override public void clear() {
|
||||
backingMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The set's iterator traverses the mappings for the first row, the
|
||||
* mappings for the second row, and so on.
|
||||
*
|
||||
* <p>Each cell is an immutable snapshot of a row key / column key / value
|
||||
* mapping, taken at the time the cell is returned by a method call to the
|
||||
* set or its iterator.
|
||||
*/
|
||||
@Override public Set<Cell<R, C, V>> cellSet() {
|
||||
return super.cellSet();
|
||||
}
|
||||
|
||||
@Override Iterator<Cell<R, C, V>> cellIterator() {
|
||||
return new CellIterator();
|
||||
}
|
||||
|
||||
private class CellIterator implements Iterator<Cell<R, C, V>> {
|
||||
final Iterator<Entry<R, Map<C, V>>> rowIterator
|
||||
= backingMap.entrySet().iterator();
|
||||
Entry<R, Map<C, V>> rowEntry;
|
||||
Iterator<Entry<C, V>> columnIterator
|
||||
= Iterators.emptyModifiableIterator();
|
||||
|
||||
@Override public boolean hasNext() {
|
||||
return rowIterator.hasNext() || columnIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override public Cell<R, C, V> next() {
|
||||
if (!columnIterator.hasNext()) {
|
||||
rowEntry = rowIterator.next();
|
||||
columnIterator = rowEntry.getValue().entrySet().iterator();
|
||||
}
|
||||
Entry<C, V> columnEntry = columnIterator.next();
|
||||
return ImmutableTable.immutableCell(
|
||||
rowEntry.getKey(), columnEntry.getKey(), columnEntry.getValue());
|
||||
}
|
||||
|
||||
@Override public void remove() {
|
||||
columnIterator.remove();
|
||||
if (rowEntry.getValue().isEmpty()) {
|
||||
rowIterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public Map<C, V> row(R rowKey) {
|
||||
return new Row(rowKey);
|
||||
}
|
||||
|
||||
class Row extends ImprovedAbstractMap<C, V> {
|
||||
final R rowKey;
|
||||
|
||||
Row(R rowKey) {
|
||||
this.rowKey = checkNotNull(rowKey);
|
||||
}
|
||||
|
||||
Map<C, V> backingRowMap;
|
||||
|
||||
Map<C, V> backingRowMap() {
|
||||
return (backingRowMap == null
|
||||
|| (backingRowMap.isEmpty() && backingMap.containsKey(rowKey)))
|
||||
? backingRowMap = computeBackingRowMap()
|
||||
: backingRowMap;
|
||||
}
|
||||
|
||||
Map<C, V> computeBackingRowMap() {
|
||||
return backingMap.get(rowKey);
|
||||
}
|
||||
|
||||
// Call this every time we perform a removal.
|
||||
void maintainEmptyInvariant() {
|
||||
if (backingRowMap() != null && backingRowMap.isEmpty()) {
|
||||
backingMap.remove(rowKey);
|
||||
backingRowMap = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
Map<C, V> backingRowMap = backingRowMap();
|
||||
return (key != null && backingRowMap != null)
|
||||
&& Maps.safeContainsKey(backingRowMap, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
Map<C, V> backingRowMap = backingRowMap();
|
||||
return (key != null && backingRowMap != null)
|
||||
? Maps.safeGet(backingRowMap, key)
|
||||
: null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(C key, V value) {
|
||||
checkNotNull(key);
|
||||
checkNotNull(value);
|
||||
if (backingRowMap != null && !backingRowMap.isEmpty()) {
|
||||
return backingRowMap.put(key, value);
|
||||
}
|
||||
return StandardTable.this.put(rowKey, key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
Map<C, V> backingRowMap = backingRowMap();
|
||||
if (backingRowMap == null) {
|
||||
return null;
|
||||
}
|
||||
V result = Maps.safeRemove(backingRowMap, key);
|
||||
maintainEmptyInvariant();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
Map<C, V> backingRowMap = backingRowMap();
|
||||
if (backingRowMap != null) {
|
||||
backingRowMap.clear();
|
||||
}
|
||||
maintainEmptyInvariant();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<Entry<C, V>> createEntrySet() {
|
||||
return new RowEntrySet();
|
||||
}
|
||||
|
||||
private final class RowEntrySet extends Maps.EntrySet<C, V> {
|
||||
@Override
|
||||
Map<C, V> map() {
|
||||
return Row.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
Map<C, V> map = backingRowMap();
|
||||
return (map == null) ? 0 : map.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<C, V>> iterator() {
|
||||
final Map<C, V> map = backingRowMap();
|
||||
if (map == null) {
|
||||
return Iterators.emptyModifiableIterator();
|
||||
}
|
||||
final Iterator<Entry<C, V>> iterator = map.entrySet().iterator();
|
||||
return new Iterator<Entry<C, V>>() {
|
||||
@Override public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
@Override public Entry<C, V> next() {
|
||||
final Entry<C, V> entry = iterator.next();
|
||||
return new ForwardingMapEntry<C, V>() {
|
||||
@Override protected Entry<C, V> delegate() {
|
||||
return entry;
|
||||
}
|
||||
@Override public V setValue(V value) {
|
||||
return super.setValue(checkNotNull(value));
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
// TODO(user): identify why this affects GWT tests
|
||||
return standardEquals(object);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
iterator.remove();
|
||||
maintainEmptyInvariant();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The returned map's views have iterators that don't support
|
||||
* {@code remove()}.
|
||||
*/
|
||||
@Override public Map<R, V> column(C columnKey) {
|
||||
return new Column(columnKey);
|
||||
}
|
||||
|
||||
private class Column extends ImprovedAbstractMap<R, V> {
|
||||
final C columnKey;
|
||||
|
||||
Column(C columnKey) {
|
||||
this.columnKey = checkNotNull(columnKey);
|
||||
}
|
||||
|
||||
@Override public V put(R key, V value) {
|
||||
return StandardTable.this.put(key, columnKey, value);
|
||||
}
|
||||
|
||||
@Override public V get(Object key) {
|
||||
return StandardTable.this.get(key, columnKey);
|
||||
}
|
||||
|
||||
@Override public boolean containsKey(Object key) {
|
||||
return StandardTable.this.contains(key, columnKey);
|
||||
}
|
||||
|
||||
@Override public V remove(Object key) {
|
||||
return StandardTable.this.remove(key, columnKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all {@code Column} mappings whose row key and value satisfy the
|
||||
* given predicate.
|
||||
*/
|
||||
boolean removeFromColumnIf(Predicate<? super Entry<R, V>> predicate) {
|
||||
boolean changed = false;
|
||||
Iterator<Entry<R, Map<C, V>>> iterator
|
||||
= backingMap.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Entry<R, Map<C, V>> entry = iterator.next();
|
||||
Map<C, V> map = entry.getValue();
|
||||
V value = map.get(columnKey);
|
||||
if (value != null
|
||||
&& predicate.test(Maps.immutableEntry(entry.getKey(), value))) {
|
||||
map.remove(columnKey);
|
||||
changed = true;
|
||||
if (map.isEmpty()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override Set<Entry<R, V>> createEntrySet() {
|
||||
return new EntrySet();
|
||||
}
|
||||
|
||||
private class EntrySet extends ImprovedAbstractSet<Entry<R, V>> {
|
||||
@Override public Iterator<Entry<R, V>> iterator() {
|
||||
return new EntrySetIterator();
|
||||
}
|
||||
|
||||
@Override public int size() {
|
||||
int size = 0;
|
||||
for (Map<C, V> map : backingMap.values()) {
|
||||
if (map.containsKey(columnKey)) {
|
||||
size++;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override public boolean isEmpty() {
|
||||
return !containsColumn(columnKey);
|
||||
}
|
||||
|
||||
@Override public void clear() {
|
||||
removeFromColumnIf(alwaysTrue());
|
||||
}
|
||||
|
||||
@Override public boolean contains(Object o) {
|
||||
if (o instanceof Entry) {
|
||||
Entry<?, ?> entry = (Entry<?, ?>) o;
|
||||
return containsMapping(entry.getKey(), columnKey, entry.getValue());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean remove(Object obj) {
|
||||
if (obj instanceof Entry) {
|
||||
Entry<?, ?> entry = (Entry<?, ?>) obj;
|
||||
return removeMapping(entry.getKey(), columnKey, entry.getValue());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean retainAll(Collection<?> c) {
|
||||
return removeFromColumnIf(not(in(c)));
|
||||
}
|
||||
}
|
||||
|
||||
private class EntrySetIterator extends AbstractIterator<Entry<R, V>> {
|
||||
final Iterator<Entry<R, Map<C, V>>> iterator
|
||||
= backingMap.entrySet().iterator();
|
||||
@Override protected Entry<R, V> computeNext() {
|
||||
while (iterator.hasNext()) {
|
||||
final Entry<R, Map<C, V>> entry = iterator.next();
|
||||
if (entry.getValue().containsKey(columnKey)) {
|
||||
return new AbstractMapEntry<R, V>() {
|
||||
@Override public R getKey() {
|
||||
return entry.getKey();
|
||||
}
|
||||
@Override public V getValue() {
|
||||
return entry.getValue().get(columnKey);
|
||||
}
|
||||
@Override public V setValue(V value) {
|
||||
return entry.getValue().put(columnKey, checkNotNull(value));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return endOfData();
|
||||
}
|
||||
}
|
||||
|
||||
@Override Set<R> createKeySet() {
|
||||
return new KeySet();
|
||||
}
|
||||
|
||||
private class KeySet extends Maps.KeySet<R, V> {
|
||||
KeySet() {
|
||||
super(Column.this);
|
||||
}
|
||||
|
||||
@Override public boolean contains(Object obj) {
|
||||
return StandardTable.this.contains(obj, columnKey);
|
||||
}
|
||||
|
||||
@Override public boolean remove(Object obj) {
|
||||
return StandardTable.this.remove(obj, columnKey) != null;
|
||||
}
|
||||
|
||||
@Override public boolean retainAll(final Collection<?> c) {
|
||||
return removeFromColumnIf(Maps.<R>keyPredicateOnEntries(not(in(c))));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Collection<V> createValues() {
|
||||
return new Values();
|
||||
}
|
||||
|
||||
private class Values extends Maps.Values<R, V> {
|
||||
Values() {
|
||||
super(Column.this);
|
||||
}
|
||||
|
||||
@Override public boolean remove(Object obj) {
|
||||
return obj != null && removeFromColumnIf(Maps.<V>valuePredicateOnEntries(equalTo(obj)));
|
||||
}
|
||||
|
||||
@Override public boolean removeAll(final Collection<?> c) {
|
||||
return removeFromColumnIf(Maps.<V>valuePredicateOnEntries(in(c)));
|
||||
}
|
||||
|
||||
@Override public boolean retainAll(final Collection<?> c) {
|
||||
return removeFromColumnIf(Maps.<V>valuePredicateOnEntries(not(in(c))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public Set<R> rowKeySet() {
|
||||
return rowMap().keySet();
|
||||
}
|
||||
|
||||
private transient Set<C> columnKeySet;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The returned set has an iterator that does not support {@code remove()}.
|
||||
*
|
||||
* <p>The set's iterator traverses the columns of the first row, the
|
||||
* columns of the second row, etc., skipping any columns that have
|
||||
* appeared previously.
|
||||
*/
|
||||
@Override
|
||||
public Set<C> columnKeySet() {
|
||||
Set<C> result = columnKeySet;
|
||||
return (result == null) ? columnKeySet = new ColumnKeySet() : result;
|
||||
}
|
||||
|
||||
private class ColumnKeySet extends TableSet<C> {
|
||||
@Override public Iterator<C> iterator() {
|
||||
return createColumnKeyIterator();
|
||||
}
|
||||
|
||||
@Override public int size() {
|
||||
return Iterators.size(iterator());
|
||||
}
|
||||
|
||||
@Override public boolean remove(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
boolean changed = false;
|
||||
Iterator<Map<C, V>> iterator = backingMap.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map<C, V> map = iterator.next();
|
||||
if (map.keySet().remove(obj)) {
|
||||
changed = true;
|
||||
if (map.isEmpty()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override public boolean removeAll(Collection<?> c) {
|
||||
checkNotNull(c);
|
||||
boolean changed = false;
|
||||
Iterator<Map<C, V>> iterator = backingMap.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map<C, V> map = iterator.next();
|
||||
// map.keySet().removeAll(c) can throw a NPE when map is a TreeMap with
|
||||
// natural ordering and c contains a null.
|
||||
if (Iterators.removeAll(map.keySet().iterator(), c)) {
|
||||
changed = true;
|
||||
if (map.isEmpty()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override public boolean retainAll(Collection<?> c) {
|
||||
checkNotNull(c);
|
||||
boolean changed = false;
|
||||
Iterator<Map<C, V>> iterator = backingMap.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map<C, V> map = iterator.next();
|
||||
if (map.keySet().retainAll(c)) {
|
||||
changed = true;
|
||||
if (map.isEmpty()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override public boolean contains(Object obj) {
|
||||
return containsColumn(obj);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an iterator that returns each column value with duplicates
|
||||
* omitted.
|
||||
*/
|
||||
Iterator<C> createColumnKeyIterator() {
|
||||
return new ColumnKeyIterator();
|
||||
}
|
||||
|
||||
private class ColumnKeyIterator extends AbstractIterator<C> {
|
||||
// Use the same map type to support TreeMaps with comparators that aren't
|
||||
// consistent with equals().
|
||||
final Map<C, V> seen = Maps.newHashMapWithExpectedSize(0);
|
||||
final Iterator<Map<C, V>> mapIterator = backingMap.values().iterator();
|
||||
Iterator<Entry<C, V>> entryIterator = Iterators.emptyIterator();
|
||||
|
||||
@Override protected C computeNext() {
|
||||
while (true) {
|
||||
if (entryIterator.hasNext()) {
|
||||
Entry<C, V> entry = entryIterator.next();
|
||||
if (!seen.containsKey(entry.getKey())) {
|
||||
seen.put(entry.getKey(), entry.getValue());
|
||||
return entry.getKey();
|
||||
}
|
||||
} else if (mapIterator.hasNext()) {
|
||||
entryIterator = mapIterator.next().entrySet().iterator();
|
||||
} else {
|
||||
return endOfData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The collection's iterator traverses the values for the first row,
|
||||
* the values for the second row, and so on.
|
||||
*/
|
||||
@Override public Collection<V> values() {
|
||||
return super.values();
|
||||
}
|
||||
|
||||
private transient Map<R, Map<C, V>> rowMap;
|
||||
|
||||
@Override public Map<R, Map<C, V>> rowMap() {
|
||||
Map<R, Map<C, V>> result = rowMap;
|
||||
return (result == null) ? rowMap = createRowMap() : result;
|
||||
}
|
||||
|
||||
Map<R, Map<C, V>> createRowMap() {
|
||||
return new RowMap();
|
||||
}
|
||||
|
||||
class RowMap extends ImprovedAbstractMap<R, Map<C, V>> {
|
||||
@Override public boolean containsKey(Object key) {
|
||||
return containsRow(key);
|
||||
}
|
||||
|
||||
// performing cast only when key is in backing map and has the correct type
|
||||
|
||||
@Override public Map<C, V> get(Object key) {
|
||||
return containsRow(key) ? row((R) key) : null;
|
||||
}
|
||||
|
||||
@Override public Map<C, V> remove(Object key) {
|
||||
return (key == null) ? null : backingMap.remove(key);
|
||||
}
|
||||
|
||||
@Override protected Set<Entry<R, Map<C, V>>> createEntrySet() {
|
||||
return new EntrySet();
|
||||
}
|
||||
|
||||
class EntrySet extends TableSet<Entry<R, Map<C, V>>> {
|
||||
@Override public Iterator<Entry<R, Map<C, V>>> iterator() {
|
||||
return Maps.asMapEntryIterator(backingMap.keySet(), new Function<R, Map<C, V>>() {
|
||||
@Override
|
||||
public Map<C, V> apply(R rowKey) {
|
||||
return row(rowKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override public int size() {
|
||||
return backingMap.size();
|
||||
}
|
||||
|
||||
@Override public boolean contains(Object obj) {
|
||||
if (obj instanceof Entry) {
|
||||
Entry<?, ?> entry = (Entry<?, ?>) obj;
|
||||
return entry.getKey() != null
|
||||
&& entry.getValue() instanceof Map
|
||||
&& Filter.safeContains(backingMap.entrySet(), entry);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean remove(Object obj) {
|
||||
if (obj instanceof Entry) {
|
||||
Entry<?, ?> entry = (Entry<?, ?>) obj;
|
||||
return entry.getKey() != null
|
||||
&& entry.getValue() instanceof Map
|
||||
&& backingMap.entrySet().remove(entry);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private transient ColumnMap columnMap;
|
||||
|
||||
@Override public Map<C, Map<R, V>> columnMap() {
|
||||
ColumnMap result = columnMap;
|
||||
return (result == null) ? columnMap = new ColumnMap() : result;
|
||||
}
|
||||
|
||||
private class ColumnMap extends ImprovedAbstractMap<C, Map<R, V>> {
|
||||
// The cast to C occurs only when the key is in the map, implying that it
|
||||
// has the correct type.
|
||||
|
||||
@Override public Map<R, V> get(Object key) {
|
||||
return containsColumn(key) ? column((C) key) : null;
|
||||
}
|
||||
|
||||
@Override public boolean containsKey(Object key) {
|
||||
return containsColumn(key);
|
||||
}
|
||||
|
||||
@Override public Map<R, V> remove(Object key) {
|
||||
return containsColumn(key) ? removeColumn(key) : null;
|
||||
}
|
||||
|
||||
@Override public Set<Entry<C, Map<R, V>>> createEntrySet() {
|
||||
return new ColumnMapEntrySet();
|
||||
}
|
||||
|
||||
@Override public Set<C> keySet() {
|
||||
return columnKeySet();
|
||||
}
|
||||
|
||||
@Override Collection<Map<R, V>> createValues() {
|
||||
return new ColumnMapValues();
|
||||
}
|
||||
|
||||
class ColumnMapEntrySet extends TableSet<Entry<C, Map<R, V>>> {
|
||||
@Override public Iterator<Entry<C, Map<R, V>>> iterator() {
|
||||
return Maps.asMapEntryIterator(columnKeySet(), new Function<C, Map<R, V>>() {
|
||||
@Override
|
||||
public Map<R, V> apply(C columnKey) {
|
||||
return column(columnKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override public int size() {
|
||||
return columnKeySet().size();
|
||||
}
|
||||
|
||||
@Override public boolean contains(Object obj) {
|
||||
if (obj instanceof Entry) {
|
||||
Entry<?, ?> entry = (Entry<?, ?>) obj;
|
||||
if (containsColumn(entry.getKey())) {
|
||||
// The cast to C occurs only when the key is in the map, implying
|
||||
// that it has the correct type.
|
||||
|
||||
C columnKey = (C) entry.getKey();
|
||||
return get(columnKey).equals(entry.getValue());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean remove(Object obj) {
|
||||
if (contains(obj)) {
|
||||
Entry<?, ?> entry = (Entry<?, ?>) obj;
|
||||
removeColumn(entry.getKey());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean removeAll(Collection<?> c) {
|
||||
/*
|
||||
* We can't inherit the normal implementation (which calls
|
||||
* Sets.removeAllImpl(Set, *Collection*) because, under some
|
||||
* circumstances, it attempts to call columnKeySet().iterator().remove,
|
||||
* which is unsupported.
|
||||
*/
|
||||
checkNotNull(c);
|
||||
return Sets.removeAllImpl(this, c.iterator());
|
||||
}
|
||||
|
||||
@Override public boolean retainAll(Collection<?> c) {
|
||||
checkNotNull(c);
|
||||
boolean changed = false;
|
||||
for (C columnKey : Lists.newArrayList(columnKeySet().iterator())) {
|
||||
if (!c.contains(Maps.immutableEntry(columnKey, column(columnKey)))) {
|
||||
removeColumn(columnKey);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
|
||||
private class ColumnMapValues extends Maps.Values<C, Map<R, V>> {
|
||||
ColumnMapValues() {
|
||||
super(ColumnMap.this);
|
||||
}
|
||||
|
||||
@Override public boolean remove(Object obj) {
|
||||
for (Entry<C, Map<R, V>> entry : ColumnMap.this.entrySet()) {
|
||||
if (entry.getValue().equals(obj)) {
|
||||
removeColumn(entry.getKey());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean removeAll(Collection<?> c) {
|
||||
checkNotNull(c);
|
||||
boolean changed = false;
|
||||
for (C columnKey : Lists.newArrayList(columnKeySet().iterator())) {
|
||||
if (c.contains(column(columnKey))) {
|
||||
removeColumn(columnKey);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override public boolean retainAll(Collection<?> c) {
|
||||
checkNotNull(c);
|
||||
boolean changed = false;
|
||||
for (C columnKey : Lists.newArrayList(columnKeySet().iterator())) {
|
||||
if (!c.contains(column(columnKey))) {
|
||||
removeColumn(columnKey);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
291
java/src/game/collect/Table.java
Normal file
291
java/src/game/collect/Table.java
Normal file
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A collection that associates an ordered pair of keys, called a row key and a
|
||||
* column key, with a single value. A table may be sparse, with only a small
|
||||
* fraction of row key / column key pairs possessing a corresponding value.
|
||||
*
|
||||
* <p>The mappings corresponding to a given row key may be viewed as a {@link
|
||||
* Map} whose keys are the columns. The reverse is also available, associating a
|
||||
* column with a row key / value map. Note that, in some implementations, data
|
||||
* access by column key may have fewer supported operations or worse performance
|
||||
* than data access by row key.
|
||||
*
|
||||
* <p>The methods returning collections or maps always return views of the
|
||||
* underlying table. Updating the table can change the contents of those
|
||||
* collections, and updating the collections will change the table.
|
||||
*
|
||||
* <p>All methods that modify the table are optional, and the views returned by
|
||||
* the table may or may not be modifiable. When modification isn't supported,
|
||||
* those methods will throw an {@link UnsupportedOperationException}.
|
||||
*
|
||||
* <p>See the Guava User Guide article on <a href=
|
||||
* "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Table">
|
||||
* {@code Table}</a>.
|
||||
*
|
||||
* @author Jared Levy
|
||||
* @param <R> the type of the table row keys
|
||||
* @param <C> the type of the table column keys
|
||||
* @param <V> the type of the mapped values
|
||||
* @since 7.0
|
||||
*/
|
||||
|
||||
public interface Table<R, C, V> {
|
||||
// TODO(jlevy): Consider adding methods similar to ConcurrentMap methods.
|
||||
|
||||
// Accessors
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the table contains a mapping with the specified
|
||||
* row and column keys.
|
||||
*
|
||||
* @param rowKey key of row to search for
|
||||
* @param columnKey key of column to search for
|
||||
*/
|
||||
boolean contains(Object rowKey, Object columnKey);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the table contains a mapping with the specified
|
||||
* row key.
|
||||
*
|
||||
* @param rowKey key of row to search for
|
||||
*/
|
||||
boolean containsRow(Object rowKey);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the table contains a mapping with the specified
|
||||
* column.
|
||||
*
|
||||
* @param columnKey key of column to search for
|
||||
*/
|
||||
boolean containsColumn(Object columnKey);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the table contains a mapping with the specified
|
||||
* value.
|
||||
*
|
||||
* @param value value to search for
|
||||
*/
|
||||
boolean containsValue(Object value);
|
||||
|
||||
/**
|
||||
* Returns the value corresponding to the given row and column keys, or
|
||||
* {@code null} if no such mapping exists.
|
||||
*
|
||||
* @param rowKey key of row to search for
|
||||
* @param columnKey key of column to search for
|
||||
*/
|
||||
V get(Object rowKey, Object columnKey);
|
||||
|
||||
/** Returns {@code true} if the table contains no mappings. */
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Returns the number of row key / column key / value mappings in the table.
|
||||
*/
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Compares the specified object with this table for equality. Two tables are
|
||||
* equal when their cell views, as returned by {@link #cellSet}, are equal.
|
||||
*/
|
||||
@Override
|
||||
boolean equals(Object obj);
|
||||
|
||||
/**
|
||||
* Returns the hash code for this table. The hash code of a table is defined
|
||||
* as the hash code of its cell view, as returned by {@link #cellSet}.
|
||||
*/
|
||||
@Override
|
||||
int hashCode();
|
||||
|
||||
// Mutators
|
||||
|
||||
/** Removes all mappings from the table. */
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Associates the specified value with the specified keys. If the table
|
||||
* already contained a mapping for those keys, the old value is replaced with
|
||||
* the specified value.
|
||||
*
|
||||
* @param rowKey row key that the value should be associated with
|
||||
* @param columnKey column key that the value should be associated with
|
||||
* @param value value to be associated with the specified keys
|
||||
* @return the value previously associated with the keys, or {@code null} if
|
||||
* no mapping existed for the keys
|
||||
*/
|
||||
V put(R rowKey, C columnKey, V value);
|
||||
|
||||
/**
|
||||
* Copies all mappings from the specified table to this table. The effect is
|
||||
* equivalent to calling {@link #put} with each row key / column key / value
|
||||
* mapping in {@code table}.
|
||||
*
|
||||
* @param table the table to add to this table
|
||||
*/
|
||||
void putAll(Table<? extends R, ? extends C, ? extends V> table);
|
||||
|
||||
/**
|
||||
* Removes the mapping, if any, associated with the given keys.
|
||||
*
|
||||
* @param rowKey row key of mapping to be removed
|
||||
* @param columnKey column key of mapping to be removed
|
||||
* @return the value previously associated with the keys, or {@code null} if
|
||||
* no such value existed
|
||||
*/
|
||||
V remove(Object rowKey, Object columnKey);
|
||||
|
||||
// Views
|
||||
|
||||
/**
|
||||
* Returns a view of all mappings that have the given row key. For each row
|
||||
* key / column key / value mapping in the table with that row key, the
|
||||
* returned map associates the column key with the value. If no mappings in
|
||||
* the table have the provided row key, an empty map is returned.
|
||||
*
|
||||
* <p>Changes to the returned map will update the underlying table, and vice
|
||||
* versa.
|
||||
*
|
||||
* @param rowKey key of row to search for in the table
|
||||
* @return the corresponding map from column keys to values
|
||||
*/
|
||||
Map<C, V> row(R rowKey);
|
||||
|
||||
/**
|
||||
* Returns a view of all mappings that have the given column key. For each row
|
||||
* key / column key / value mapping in the table with that column key, the
|
||||
* returned map associates the row key with the value. If no mappings in the
|
||||
* table have the provided column key, an empty map is returned.
|
||||
*
|
||||
* <p>Changes to the returned map will update the underlying table, and vice
|
||||
* versa.
|
||||
*
|
||||
* @param columnKey key of column to search for in the table
|
||||
* @return the corresponding map from row keys to values
|
||||
*/
|
||||
Map<R, V> column(C columnKey);
|
||||
|
||||
/**
|
||||
* Returns a set of all row key / column key / value triplets. Changes to the
|
||||
* returned set will update the underlying table, and vice versa. The cell set
|
||||
* does not support the {@code add} or {@code addAll} methods.
|
||||
*
|
||||
* @return set of table cells consisting of row key / column key / value
|
||||
* triplets
|
||||
*/
|
||||
Set<Cell<R, C, V>> cellSet();
|
||||
|
||||
/**
|
||||
* Returns a set of row keys that have one or more values in the table.
|
||||
* Changes to the set will update the underlying table, and vice versa.
|
||||
*
|
||||
* @return set of row keys
|
||||
*/
|
||||
Set<R> rowKeySet();
|
||||
|
||||
/**
|
||||
* Returns a set of column keys that have one or more values in the table.
|
||||
* Changes to the set will update the underlying table, and vice versa.
|
||||
*
|
||||
* @return set of column keys
|
||||
*/
|
||||
Set<C> columnKeySet();
|
||||
|
||||
/**
|
||||
* Returns a collection of all values, which may contain duplicates. Changes
|
||||
* to the returned collection will update the underlying table, and vice
|
||||
* versa.
|
||||
*
|
||||
* @return collection of values
|
||||
*/
|
||||
Collection<V> values();
|
||||
|
||||
/**
|
||||
* Returns a view that associates each row key with the corresponding map from
|
||||
* column keys to values. Changes to the returned map will update this table.
|
||||
* The returned map does not support {@code put()} or {@code putAll()}, or
|
||||
* {@code setValue()} on its entries.
|
||||
*
|
||||
* <p>In contrast, the maps returned by {@code rowMap().get()} have the same
|
||||
* behavior as those returned by {@link #row}. Those maps may support {@code
|
||||
* setValue()}, {@code put()}, and {@code putAll()}.
|
||||
*
|
||||
* @return a map view from each row key to a secondary map from column keys to
|
||||
* values
|
||||
*/
|
||||
Map<R, Map<C, V>> rowMap();
|
||||
|
||||
/**
|
||||
* Returns a view that associates each column key with the corresponding map
|
||||
* from row keys to values. Changes to the returned map will update this
|
||||
* table. The returned map does not support {@code put()} or {@code putAll()},
|
||||
* or {@code setValue()} on its entries.
|
||||
*
|
||||
* <p>In contrast, the maps returned by {@code columnMap().get()} have the
|
||||
* same behavior as those returned by {@link #column}. Those maps may support
|
||||
* {@code setValue()}, {@code put()}, and {@code putAll()}.
|
||||
*
|
||||
* @return a map view from each column key to a secondary map from row keys to
|
||||
* values
|
||||
*/
|
||||
Map<C, Map<R, V>> columnMap();
|
||||
|
||||
/**
|
||||
* Row key / column key / value triplet corresponding to a mapping in a table.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
interface Cell<R, C, V> {
|
||||
/**
|
||||
* Returns the row key of this cell.
|
||||
*/
|
||||
R getRowKey();
|
||||
|
||||
/**
|
||||
* Returns the column key of this cell.
|
||||
*/
|
||||
C getColumnKey();
|
||||
|
||||
/**
|
||||
* Returns the value of this cell.
|
||||
*/
|
||||
V getValue();
|
||||
|
||||
/**
|
||||
* Compares the specified object with this cell for equality. Two cells are
|
||||
* equal when they have equal row keys, column keys, and values.
|
||||
*/
|
||||
@Override
|
||||
boolean equals(Object obj);
|
||||
|
||||
/**
|
||||
* Returns the hash code of this cell.
|
||||
*
|
||||
* <p>The hash code of a table cell is equal to {@link
|
||||
* Objects#hashCode}{@code (e.getRowKey(), e.getColumnKey(), e.getValue())}.
|
||||
*/
|
||||
@Override
|
||||
int hashCode();
|
||||
}
|
||||
}
|
53
java/src/game/collect/TransformedIterator.java
Normal file
53
java/src/game/collect/TransformedIterator.java
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (C) 2012 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import static game.collect.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* An iterator that transforms a backing iterator; for internal use. This avoids
|
||||
* the object overhead of constructing a {@link Function} for internal methods.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
|
||||
abstract class TransformedIterator<F, T> implements Iterator<T> {
|
||||
final Iterator<? extends F> backingIterator;
|
||||
|
||||
TransformedIterator(Iterator<? extends F> backingIterator) {
|
||||
this.backingIterator = checkNotNull(backingIterator);
|
||||
}
|
||||
|
||||
abstract T transform(F from);
|
||||
|
||||
@Override
|
||||
public final boolean hasNext() {
|
||||
return backingIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T next() {
|
||||
return transform(backingIterator.next());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void remove() {
|
||||
backingIterator.remove();
|
||||
}
|
||||
}
|
43
java/src/game/collect/UnmodifiableIterator.java
Normal file
43
java/src/game/collect/UnmodifiableIterator.java
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* An iterator that does not support {@link #remove}.
|
||||
*
|
||||
* @author Jared Levy
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
|
||||
public abstract class UnmodifiableIterator<E> implements Iterator<E> {
|
||||
/** Constructor for use by subclasses. */
|
||||
protected UnmodifiableIterator() {}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the underlying data unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
53
java/src/game/collect/UnmodifiableListIterator.java
Normal file
53
java/src/game/collect/UnmodifiableListIterator.java
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Guava Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package game.collect;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
||||
/**
|
||||
* A list iterator that does not support {@link #remove}, {@link #add}, or
|
||||
* {@link #set}.
|
||||
*
|
||||
* @since 7.0
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
|
||||
abstract class UnmodifiableListIterator<E>
|
||||
extends UnmodifiableIterator<E> implements ListIterator<E> {
|
||||
/** Constructor for use by subclasses. */
|
||||
protected UnmodifiableListIterator() {}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the underlying data unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated @Override public final void add(E e) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the underlying data unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated @Override public final void set(E e) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ package game.color;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import game.collect.Maps;
|
||||
|
||||
import game.properties.IStringSerializable;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.command;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import game.collect.Lists;
|
||||
|
||||
public abstract class ArgumentParser {
|
||||
public static String[][] splitString(String str) {
|
||||
|
|
|
@ -4,8 +4,8 @@ import java.lang.reflect.Method;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import game.collect.Lists;
|
||||
import game.collect.Maps;
|
||||
|
||||
public class CachedExecutable {
|
||||
private final Executable executable;
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.command;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import game.collect.Maps;
|
||||
|
||||
public class EnumParser<T> extends DefaultingParser {
|
||||
private final Class<T> clazz;
|
||||
|
|
|
@ -4,9 +4,9 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import game.collect.Lists;
|
||||
import game.collect.Maps;
|
||||
import game.collect.Sets;
|
||||
|
||||
public class ScriptArgs {
|
||||
private final String command;
|
||||
|
|
|
@ -6,8 +6,8 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import game.collect.Lists;
|
||||
import game.collect.Maps;
|
||||
|
||||
import game.Server;
|
||||
import game.color.TextColor;
|
||||
|
|
|
@ -5,8 +5,8 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import game.collect.Lists;
|
||||
import game.collect.Maps;
|
||||
|
||||
import game.command.DoubleParser.DefType;
|
||||
import game.world.Vec3;
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.command;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import game.collect.Lists;
|
||||
|
||||
import game.dimension.Dimension;
|
||||
import game.world.WorldServer;
|
||||
|
|
|
@ -4,7 +4,7 @@ import java.util.List;
|
|||
import java.util.Map.Entry;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import game.collect.Lists;
|
||||
|
||||
import game.command.ArgumentParser;
|
||||
import game.command.CachedExecutable;
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.command.commands;
|
|||
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import game.collect.Sets;
|
||||
|
||||
import game.command.ScriptEnvironment;
|
||||
import game.command.ScriptException;
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.dimension;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import game.collect.Maps;
|
||||
|
||||
public enum DimType {
|
||||
STAR("star", "Stern %s", true, false, false, false, false, false, true),
|
||||
|
|
|
@ -4,9 +4,9 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import game.collect.Lists;
|
||||
import game.collect.Maps;
|
||||
import game.collect.Sets;
|
||||
|
||||
import game.biome.Biome;
|
||||
import game.block.LeavesType;
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.dimension;
|
|||
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import game.collect.Sets;
|
||||
|
||||
public final class Domain extends Nameable implements Comparable<Domain> {
|
||||
public final String id;
|
||||
|
|
|
@ -2,7 +2,7 @@ package game.dimension;
|
|||
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import game.collect.Sets;
|
||||
|
||||
public final class Galaxy extends Nameable implements Comparable<Galaxy> {
|
||||
public final String id;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue