/** * * Copyright 2008 - 2011 * * 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. * * @project loon * @author cping * @email:javachenpeng@yahoo.com * @version 0.1 */ package loon.component; import loon.LSystem; import loon.utils.CollectionUtils; import loon.utils.LIterator; public class ActorSet { private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) { throw LSystem.runThrow("Required array size too large"); } return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } public void clear() { LIterator<Actor> e = iterator(); while (e.hasNext()) { e.next(); e.remove(); } } public Actor[] toArray() { Actor[] r = new Actor[size()]; LIterator<Actor> it = iterator(); for (int i = 0; i < r.length; i++) { if (!it.hasNext()) { return CollectionUtils.copyOf(r, i); } r[i] = it.next(); } return it.hasNext() ? finishToArray(r, it) : r; } private static Actor[] finishToArray(Actor[] r, LIterator<Actor> it) { int i = r.length; while (it.hasNext()) { int cap = r.length; if (i == cap) { int newCap = cap + (cap >> 1) + 1; if (newCap - MAX_ARRAY_SIZE > 0) { newCap = hugeCapacity(cap + 1); } r = CollectionUtils.copyOf(r, newCap); } r[i++] = (Actor) it.next(); } return (i == r.length) ? r : CollectionUtils.copyOf(r, i); } private ActorSet.ListNode listHeadTail = new ActorSet.ListNode(); private ActorSet.ListNode[] hashMap = new ActorSet.ListNode[0]; private int numActors = 0; private int code = 0; @Override public int hashCode() { return this.code; } public boolean add(Actor actor) { if (this.contains(actor)) { return false; } else { ++this.numActors; ActorSet.ListNode newNode = new ActorSet.ListNode(actor, this.listHeadTail.prev); int seq = actor.getSequenceNumber(); if (this.numActors >= 2 * this.hashMap.length) { this.resize(); } else { int hash = seq % this.hashMap.length; ActorSet.ListNode hashHead = this.hashMap[hash]; this.hashMap[hash] = newNode; newNode.setHashListHead(hashHead); } this.code += seq; return true; } } public void addAll(Object[] o) { int size = o.length; this.numActors = size; this.resize(); for (int i = 0; i < size; i++) { Actor actor = (Actor) o[i]; ActorSet.ListNode newNode = new ActorSet.ListNode(actor, this.listHeadTail.prev); int seq = actor.getSequenceNumber(); int hash = seq % this.hashMap.length; ActorSet.ListNode hashHead = this.hashMap[hash]; this.hashMap[hash] = newNode; newNode.setHashListHead(hashHead); this.code += seq; } } private void resize(int size) { this.hashMap = new ActorSet.ListNode[size]; for (ActorSet.ListNode currentActor = this.listHeadTail.next; currentActor != this.listHeadTail; currentActor = currentActor.next) { int seq = currentActor.actor.getSequenceNumber(); int hash = seq % size; ActorSet.ListNode hashHead = this.hashMap[hash]; this.hashMap[hash] = currentActor; currentActor.setHashListHead(hashHead); } } private void resize() { resize(this.numActors); } public boolean contains(Actor actor) { return this.getActorNode(actor) != null; } private ActorSet.ListNode getActorNode(Actor actor) { if (this.hashMap.length == 0) { return null; } else { int seq = actor.getSequenceNumber(); int hash = seq % this.hashMap.length; ActorSet.ListNode hashHead = this.hashMap[hash]; if (hashHead == null) { return null; } else if (hashHead.actor == actor) { return hashHead; } else { for (ActorSet.ListNode curNode = hashHead.nextHash; curNode != hashHead; curNode = curNode.nextHash) { if (curNode.actor == actor) { return curNode; } } return null; } } } public boolean remove(Actor actor) { ActorSet.ListNode actorNode = this.getActorNode(actor); if (actorNode != null) { this.remove(actorNode); this.code -= actor.getSequenceNumber(); return true; } else { return false; } } private void remove(ActorSet.ListNode actorNode) { int seq = actorNode.actor.getSequenceNumber(); int hash = seq % this.hashMap.length; if (this.hashMap[hash] == actorNode) { this.hashMap[hash] = actorNode.nextHash; if (this.hashMap[hash] == actorNode) { this.hashMap[hash] = null; } } actorNode.remove(); --this.numActors; if (this.numActors <= this.hashMap.length / 2) { this.resize(); } } public int size() { return this.numActors; } public LIterator<Actor> iterator() { return new ActorSet.ActorSetIterator(this); } private class ListNode { Actor actor; ActorSet.ListNode next; ActorSet.ListNode prev; ActorSet.ListNode nextHash; ActorSet.ListNode prevHash; public ListNode() { this.next = this; this.prev = this; } public ListNode(Actor actor, ActorSet.ListNode listTail) { this.actor = actor; this.next = listTail.next; this.prev = listTail; listTail.next = this; this.next.prev = this; } public void setHashListHead(ActorSet.ListNode oldHead) { if (oldHead == null) { this.nextHash = this; this.prevHash = this; } else { this.nextHash = oldHead; this.prevHash = oldHead.prevHash; oldHead.prevHash = this; this.prevHash.nextHash = this; } } public void remove() { this.next.prev = this.prev; this.prev.next = this.next; this.nextHash.prevHash = this.prevHash; this.prevHash.nextHash = this.nextHash; } } private class ActorSetIterator implements LIterator<Actor> { ActorSet.ListNode currentNode; ActorSet actorSet; ActorSetIterator(ActorSet node) { this.currentNode = node.listHeadTail; this.actorSet = node; } @Override public boolean hasNext() { return this.currentNode.next != actorSet.listHeadTail; } @Override public Actor next() { this.currentNode = this.currentNode.next; return this.currentNode.actor; } @Override public void remove() { actorSet.remove(this.currentNode); } } }