refactor MovableGridRingList
This commit is contained in:
@@ -219,7 +219,7 @@ public class RenderBufferHandler {
|
||||
MovableGridRingList<LodRenderSection> referenceList = target.getRingList(topDetail);
|
||||
Pos2D center = referenceList.getCenter();
|
||||
//boolean moved = renderBufferNodes.getCenterBlockPos().x != center.x || renderBufferNodes.getCenterBlockPos().y != center.y;
|
||||
renderBufferNodes.move(center.x, center.y, RenderBufferNode::close); // Note: may lock the list
|
||||
renderBufferNodes.moveTo(center.x, center.y, RenderBufferNode::close); // Note: may lock the list
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -32,13 +32,16 @@ import java.util.function.Consumer;
|
||||
|
||||
public class MovableGridRingList<T> extends ArrayList<T> implements List<T>
|
||||
{
|
||||
/** the position of this grid closest to negative x/z infinity */
|
||||
private final AtomicReference<Pos2D> minPosRef = new AtomicReference<>();
|
||||
|
||||
private final AtomicReference<Pos2D> pos = new AtomicReference<>();
|
||||
|
||||
private final int halfSize;
|
||||
/** width of this grid list */
|
||||
private final int size;
|
||||
private final int halfSize;
|
||||
|
||||
private final ReentrantReadWriteLock moveLock = new ReentrantReadWriteLock();
|
||||
|
||||
/** used to iterate over each item in the list in an in-to-out order */
|
||||
private Pos2D[] ringIteratorList = null;
|
||||
|
||||
|
||||
@@ -54,17 +57,399 @@ public class MovableGridRingList<T> extends ArrayList<T> implements List<T>
|
||||
|
||||
this.size = halfSize * 2 + 1;
|
||||
this.halfSize = halfSize;
|
||||
this.pos.set(new Pos2D(centerX-halfSize, centerY-halfSize));
|
||||
this.minPosRef.set(new Pos2D(centerX-halfSize, centerY-halfSize));
|
||||
this.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//=====================//
|
||||
// getters and setters //
|
||||
//=====================//
|
||||
|
||||
/** see {@link MovableGridRingList#get(int, int)} for full documentation */
|
||||
public T get(Pos2D pos) { return this.get(pos.x, pos.y); }
|
||||
/** returns null if x,y is outside the grid */
|
||||
public T get(int x, int y)
|
||||
{
|
||||
Pos2D min = this.minPosRef.get();
|
||||
if (!this._inRangeAcquired(x, y, min))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
this.moveLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
Pos2D newMin = this.minPosRef.get();
|
||||
// Use EXACT compare here
|
||||
if (min!=newMin)
|
||||
{
|
||||
if (!this._inRangeAcquired(x, y, newMin))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return this._getUnsafe(x, y);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.moveLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** see {@link MovableGridRingList#set(int, int, T)} for full documentation */
|
||||
public boolean set(Pos2D pos, T item) { return this.set(pos.x, pos.y, item); }
|
||||
/** returns false if x,y is outside the grid */
|
||||
public boolean set(int x, int y, T item)
|
||||
{
|
||||
Pos2D min = this.minPosRef.get();
|
||||
if (!this._inRangeAcquired(x, y, min))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this.moveLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
Pos2D newMin = this.minPosRef.get();
|
||||
// Use EXACT compare here
|
||||
if (min!=newMin)
|
||||
{
|
||||
if (!this._inRangeAcquired(x, y, newMin))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this._setUnsafe(x, y, item);
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.moveLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/** see {@link MovableGridRingList#setChained(int, int, T)} for full documentation */
|
||||
public T setChained(Pos2D pos, T item) { return this.setChained(pos.x, pos.y, item); }
|
||||
/**
|
||||
* returns null if x,y is outside the grid
|
||||
* Otherwise, returns the new value
|
||||
*/
|
||||
public T setChained(int x, int y, T item) { return this.set(x,y,item) ? item : null; }
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// list modifiers //
|
||||
//================//
|
||||
|
||||
/** see {@link MovableGridRingList#swap(int, int, T)} for full documentation */
|
||||
public T swap(Pos2D pos, T item) { return this.swap(pos.x, pos.y, item); }
|
||||
/** returns the input item if x,y is outside the grid */
|
||||
public T swap(int x, int y, T item)
|
||||
{
|
||||
Pos2D min = this.minPosRef.get();
|
||||
if (!this._inRangeAcquired(x, y, min))
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
this.moveLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
Pos2D newMin = this.minPosRef.get();
|
||||
// Use EXACT compare here
|
||||
if (min!=newMin)
|
||||
{
|
||||
if (!this._inRangeAcquired(x, y, newMin))
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return this._swapUnsafe(x, y, item);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.moveLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** see {@link MovableGridRingList#remove(int, int)} for full documentation */
|
||||
public T remove(Pos2D pos) { return this.remove(pos.x, pos.y); }
|
||||
/** remove and return the item at x,y; returns null if the x,y are outside the grid */
|
||||
public T remove(int x, int y) { return this.swap(x, y, null); }
|
||||
|
||||
|
||||
|
||||
/** see {@link MovableGridRingList#clear(Consumer)} for full documentation */
|
||||
@Override
|
||||
public void clear() { this.clear(null); }
|
||||
/** @param consumer the consumer run on each item before it is removed from the list */
|
||||
public void clear(Consumer<? super T> consumer)
|
||||
{
|
||||
this.moveLock.writeLock().lock();
|
||||
try
|
||||
{
|
||||
if (consumer != null)
|
||||
{
|
||||
super.forEach((item) ->
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
consumer.accept(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
super.clear();
|
||||
super.ensureCapacity(this.size * this.size);
|
||||
// TODO why are we filling the array will nulls? everything should already be null after the clear
|
||||
for (int i = 0; i < this.size * this.size; i++)
|
||||
{
|
||||
super.add(null);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.moveLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** see {@link MovableGridRingList#moveTo(int, int, Consumer)} for full documentation */
|
||||
public boolean moveTo(int newCenterX, int newCenterY) { return this.moveTo(newCenterX, newCenterY, null); }
|
||||
/** Returns true if the grid was successfully moved, false otherwise */
|
||||
public boolean moveTo(int newCenterX, int newCenterY, Consumer<? super T> consumer)
|
||||
{
|
||||
Pos2D cPos = this.minPosRef.get();
|
||||
int newMinX = newCenterX - this.halfSize;
|
||||
int newMinY = newCenterY - this.halfSize;
|
||||
if (cPos.x == newMinX && cPos.y == newMinY)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this.moveLock.writeLock().lock();
|
||||
try
|
||||
{
|
||||
cPos = this.minPosRef.get();
|
||||
int deltaX = newMinX - cPos.x;
|
||||
int deltaY = newMinY - cPos.y;
|
||||
if (deltaX == 0 && deltaY == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the x or z offset is equal to or greater than
|
||||
// the total width, just delete the current data
|
||||
// and update the pos
|
||||
if (Math.abs(deltaX) >= this.size || Math.abs(deltaY) >= this.size)
|
||||
{
|
||||
this.clear(consumer);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int x = 0; x < this.size; x++)
|
||||
{
|
||||
for (int y = 0; y < this.size; y++)
|
||||
{
|
||||
if (x - deltaX < 0
|
||||
|| y - deltaY < 0
|
||||
|| x - deltaX >= this.size
|
||||
|| y - deltaY >= this.size)
|
||||
{
|
||||
T item = this._swapUnsafe(x+cPos.x, y+cPos.y, null);
|
||||
if (item != null && consumer != null)
|
||||
{
|
||||
consumer.accept(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.minPosRef.set(new Pos2D(newMinX, newMinY));
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.moveLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==================//
|
||||
// position getters //
|
||||
//==================//
|
||||
|
||||
public Pos2D getCenter() { return new Pos2D(this.minPosRef.get().x + this.halfSize, this.minPosRef.get().y + this.halfSize); }
|
||||
|
||||
public Pos2D getMinPosInRange() { return this.minPosRef.get(); }
|
||||
public Pos2D getMaxPosInRange() { return new Pos2D(this.minPosRef.get().x + this.size-1, this.minPosRef.get().y + this.size-1); }
|
||||
|
||||
public int getSize() { return this.size; }
|
||||
public int getHalfSize() { return this.halfSize; }
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper methods //
|
||||
//================//
|
||||
|
||||
/**
|
||||
* Warning: Be careful with race conditions!
|
||||
* The grid may move after this query!
|
||||
*/
|
||||
public boolean inRange(int x, int y)
|
||||
{
|
||||
Pos2D minPos = this.minPosRef.get();
|
||||
return (x>=minPos.x
|
||||
&& x<minPos.x+this.size
|
||||
&& y>=minPos.y
|
||||
&& y<minPos.y+this.size);
|
||||
}
|
||||
|
||||
private boolean _inRangeAcquired(int x, int y, Pos2D min)
|
||||
{
|
||||
return (x>=min.x
|
||||
&& x<min.x+this.size
|
||||
&& y>=min.y
|
||||
&& y<min.y+this.size);
|
||||
}
|
||||
|
||||
private T _getUnsafe(int x, int y) { return super.get(Math.floorMod(x, this.size) + Math.floorMod(y, this.size)*this.size); }
|
||||
private void _setUnsafe(int x, int y, T item) { super.set(Math.floorMod(x, this.size) + Math.floorMod(y, this.size)*this.size, item); }
|
||||
private T _swapUnsafe(int x, int y, T item) { return super.set(Math.floorMod(x, this.size) + Math.floorMod(y, this.size)*this.size, item); }
|
||||
|
||||
|
||||
// TODO: implement this
|
||||
/*
|
||||
// do a compare and set
|
||||
public boolean compareAndSet(int x, int y, T expected, T toBeSet) {
|
||||
Pos min = pos.get();
|
||||
if (!_inRangeAquired(x, y, min)) return false;
|
||||
moveLock.readLock().lock();
|
||||
try {
|
||||
Pos newMin = pos.get();
|
||||
// Use EXECT compare here
|
||||
if (min!=newMin)
|
||||
if (!_inRangeAquired(x, y, newMin)) return false;
|
||||
return _compareAndSetUnsafe(x, y, expected, toBeSet);
|
||||
} finally {
|
||||
moveLock.readLock().unlock();
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// iterators //
|
||||
//===========//
|
||||
|
||||
// TODO all iterators should either:
|
||||
// A. treat nulls the same way, either passing them into the consumers to skipping them
|
||||
// B. add the option to either skip or pass in nulls
|
||||
|
||||
|
||||
/**
|
||||
* TODO: Use MutablePos2D in the future
|
||||
* Will pass in null entries
|
||||
*/
|
||||
public void forEachPos(BiConsumer<? super T, Pos2D> consumer)
|
||||
{
|
||||
this.moveLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
Pos2D min = this.minPosRef.get();
|
||||
for (int x = min.x; x < min.x + this.size; x++)
|
||||
{
|
||||
for (int y = min.y; y < min.y + this.size; y++)
|
||||
{
|
||||
T t = this._getUnsafe(x, y);
|
||||
consumer.accept(t, new Pos2D(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.moveLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Use MutablePos2D in the future
|
||||
* Will skip null entries
|
||||
*/
|
||||
public void forEachOrdered(Consumer<? super T> consumer)
|
||||
{
|
||||
// create the iterator if necessary
|
||||
if (this.ringIteratorList == null)
|
||||
{
|
||||
this.createRingIteratorList();
|
||||
}
|
||||
|
||||
this.moveLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
Pos2D min = this.minPosRef.get();
|
||||
for (Pos2D offset : this.ringIteratorList)
|
||||
{
|
||||
T item = this._getUnsafe(min.x + offset.x, min.y + offset.y);
|
||||
if (item != null)
|
||||
{
|
||||
consumer.accept(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.moveLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Use MutablePos2D in the future
|
||||
* Will pass in null entries
|
||||
*/
|
||||
public void forEachPosOrdered(BiConsumer<? super T, Pos2D> consumer)
|
||||
{
|
||||
// create the iterator if necessary
|
||||
if (this.ringIteratorList == null)
|
||||
{
|
||||
this.createRingIteratorList();
|
||||
}
|
||||
|
||||
this.moveLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
Pos2D min = this.minPosRef.get();
|
||||
for (Pos2D offset : this.ringIteratorList)
|
||||
{
|
||||
LodUtil.assertTrue(this._inRangeAcquired(min.x + offset.x, min.y + offset.y, min));
|
||||
T t = this._getUnsafe(min.x + offset.x, min.y + offset.y);
|
||||
consumer.accept(t, new Pos2D(min.x + offset.x, min.y + offset.y));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.moveLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* TODO: Check if this needs to be synchronized
|
||||
* <br>
|
||||
* FIXME: Make all usage of this class do stuff relative to the minPos instead of the center
|
||||
*/
|
||||
private void buildRingIteratorList()
|
||||
private void createRingIteratorList()
|
||||
{
|
||||
this.ringIteratorList = null;
|
||||
Pos2D[] posArray = new Pos2D[this.size*this.size];
|
||||
@@ -103,353 +488,14 @@ public class MovableGridRingList<T> extends ArrayList<T> implements List<T>
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// base methods //
|
||||
//==============//
|
||||
|
||||
@Override
|
||||
public void clear() { this.clear(null); }
|
||||
/** @param consumer the consumer run on each item before it is removed from the list */
|
||||
public void clear(Consumer<? super T> consumer)
|
||||
{
|
||||
this.moveLock.writeLock().lock();
|
||||
try
|
||||
{
|
||||
if (consumer != null)
|
||||
{
|
||||
super.forEach((t) ->
|
||||
{
|
||||
if (t != null)
|
||||
{
|
||||
consumer.accept(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
super.clear();
|
||||
super.ensureCapacity(this.size * this.size);
|
||||
// TODO why are we filling the array will nulls? everything should already be null after the clear
|
||||
for (int i = 0; i < this.size * this.size; i++)
|
||||
{
|
||||
super.add(null);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.moveLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Pos2D getCenter()
|
||||
{
|
||||
Pos2D bottom = this.pos.get();
|
||||
return new Pos2D(bottom.x + this.halfSize, bottom.y + this.halfSize);
|
||||
}
|
||||
public Pos2D getMinInRange() { return this.pos.get(); }
|
||||
public Pos2D getMaxInRange() {
|
||||
Pos2D bottom = this.pos.get();
|
||||
return new Pos2D(bottom.x + this.size-1, bottom.y + this.size-1);
|
||||
}
|
||||
public int getSize() { return this.size; }
|
||||
public int getHalfSize() { return this.halfSize; }
|
||||
|
||||
/**
|
||||
* Warning: Be careful with race conditions!
|
||||
* The grid may move after this query!
|
||||
*/
|
||||
public boolean inRange(int x, int y)
|
||||
{
|
||||
Pos2D minPos = this.pos.get();
|
||||
return (x>=minPos.x
|
||||
&& x<minPos.x+this.size
|
||||
&& y>=minPos.y
|
||||
&& y<minPos.y+this.size);
|
||||
}
|
||||
private boolean _inRangeAquired(int x, int y, Pos2D min)
|
||||
{
|
||||
return (x>=min.x
|
||||
&& x<min.x+this.size
|
||||
&& y>=min.y
|
||||
&& y<min.y+this.size);
|
||||
}
|
||||
private T _getUnsafe(int x, int y)
|
||||
{
|
||||
return super.get(Math.floorMod(x, this.size) + Math.floorMod(y, this.size)*this.size);
|
||||
}
|
||||
private void _setUnsafe(int x, int y, T t)
|
||||
{
|
||||
super.set(Math.floorMod(x, this.size) + Math.floorMod(y, this.size)*this.size, t);
|
||||
}
|
||||
private T _swapUnsafe(int x, int y, T t)
|
||||
{
|
||||
return super.set(Math.floorMod(x, this.size) + Math.floorMod(y, this.size)*this.size, t);
|
||||
}
|
||||
|
||||
/** returns null if x,y is outside the grid */
|
||||
public T get(int x, int y)
|
||||
{
|
||||
Pos2D min = pos.get();
|
||||
if (!this._inRangeAquired(x, y, min))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
this.moveLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
Pos2D newMin = pos.get();
|
||||
// Use EXECT compare here
|
||||
if (min!=newMin)
|
||||
{
|
||||
if (!_inRangeAquired(x, y, newMin))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return this._getUnsafe(x, y);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.moveLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/** returns false if x,y is outside the grid */
|
||||
public boolean set(int x, int y, T t)
|
||||
{
|
||||
Pos2D min = this.pos.get();
|
||||
if (!this._inRangeAquired(x, y, min))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this.moveLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
Pos2D newMin = this.pos.get();
|
||||
// Use EXACT compare here
|
||||
if (min!=newMin)
|
||||
{
|
||||
if (!this._inRangeAquired(x, y, newMin))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this._setUnsafe(x, y, t);
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.moveLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// return input t if x,y is outside of the grid
|
||||
public T swap(int x, int y, T t)
|
||||
{
|
||||
Pos2D min = this.pos.get();
|
||||
if (!this._inRangeAquired(x, y, min))
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
this.moveLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
Pos2D newMin = this.pos.get();
|
||||
// Use EXACT compare here
|
||||
if (min!=newMin)
|
||||
{
|
||||
if (!this._inRangeAquired(x, y, newMin))
|
||||
{
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return this._swapUnsafe(x, y, t);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.moveLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public T remove(int x, int y) { return this.swap(x, y, null); }
|
||||
|
||||
public T get(Pos2D p) { return this.get(p.x, p.y); }
|
||||
public boolean set(Pos2D p, T t) { return this.set(p.x, p.y, t); }
|
||||
public T swap(Pos2D p, T t) { return this.swap(p.x, p.y, t); }
|
||||
public T remove(Pos2D p) { return this.remove(p.x, p.y); }
|
||||
|
||||
|
||||
// TODO: implement this
|
||||
/*
|
||||
// do a compare and set
|
||||
public boolean compareAndSet(int x, int y, T expected, T toBeSet) {
|
||||
Pos min = pos.get();
|
||||
if (!_inRangeAquired(x, y, min)) return false;
|
||||
moveLock.readLock().lock();
|
||||
try {
|
||||
Pos newMin = pos.get();
|
||||
// Use EXECT compare here
|
||||
if (min!=newMin)
|
||||
if (!_inRangeAquired(x, y, newMin)) return false;
|
||||
return _compareAndSetUnsafe(x, y, expected, toBeSet);
|
||||
} finally {
|
||||
moveLock.readLock().unlock();
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* return null if x,y is outside of the grid
|
||||
* Otherwise, return the new value (for chaining)
|
||||
*/
|
||||
public T setChained(int x, int y, T t) { return this.set(x,y,t) ? t : null; }
|
||||
public T setChained(Pos2D p, T t) { return this.setChained(p.x, p.y, t); }
|
||||
|
||||
/** Returns true if the grid was successfully moved, false otherwise */
|
||||
public boolean move(int newCenterX, int newCenterY) { return this.move(newCenterX, newCenterY, null); }
|
||||
|
||||
public boolean move(int newCenterX, int newCenterY, Consumer<? super T> consumer)
|
||||
{
|
||||
Pos2D cPos = this.pos.get();
|
||||
int newMinX = newCenterX - this.halfSize;
|
||||
int newMinY = newCenterY - this.halfSize;
|
||||
if (cPos.x == newMinX && cPos.y == newMinY)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this.moveLock.writeLock().lock();
|
||||
try
|
||||
{
|
||||
cPos = this.pos.get();
|
||||
int deltaX = newMinX - cPos.x;
|
||||
int deltaY = newMinY - cPos.y;
|
||||
if (deltaX == 0 && deltaY == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the x or z offset is equal to or greater than
|
||||
// the total width, just delete the current data
|
||||
// and update the pos
|
||||
if (Math.abs(deltaX) >= this.size || Math.abs(deltaY) >= this.size)
|
||||
{
|
||||
this.clear(consumer);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int x = 0; x < this.size; x++)
|
||||
{
|
||||
for (int y = 0; y < this.size; y++)
|
||||
{
|
||||
if (x - deltaX < 0 || y - deltaY < 0 || x - deltaX >= this.size || y - deltaY >= this.size)
|
||||
{
|
||||
T t = this._swapUnsafe(x + cPos.x, y + cPos.y, null);
|
||||
if (t != null && consumer != null)
|
||||
{
|
||||
consumer.accept(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.pos.set(new Pos2D(newMinX, newMinY));
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.moveLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Use MutablePos2D in the future
|
||||
* Will pass in null entries
|
||||
*/
|
||||
public void forEachPos(BiConsumer<? super T, Pos2D> consumer)
|
||||
{
|
||||
this.moveLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
Pos2D min = this.pos.get();
|
||||
for (int x = min.x; x < min.x + this.size; x++)
|
||||
{
|
||||
for (int y = min.y; y < min.y + this.size; y++)
|
||||
{
|
||||
T t = this._getUnsafe(x, y);
|
||||
consumer.accept(t, new Pos2D(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.moveLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Use MutablePos2D in the future
|
||||
* Will skip null entries
|
||||
*/
|
||||
public void forEachOrdered(Consumer<? super T> consumer)
|
||||
{
|
||||
if (this.ringIteratorList == null)
|
||||
{
|
||||
this.buildRingIteratorList();
|
||||
}
|
||||
|
||||
this.moveLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
Pos2D min = this.pos.get();
|
||||
for (Pos2D offset : this.ringIteratorList)
|
||||
{
|
||||
T t = this._getUnsafe(min.x + offset.x, min.y + offset.y);
|
||||
if (t != null)
|
||||
{
|
||||
consumer.accept(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.moveLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Use MutablePos2D in the future
|
||||
* Will pass in null entries
|
||||
*/
|
||||
public void forEachPosOrdered(BiConsumer<? super T, Pos2D> consumer)
|
||||
{
|
||||
if (this.ringIteratorList == null)
|
||||
{
|
||||
this.buildRingIteratorList();
|
||||
}
|
||||
|
||||
this.moveLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
Pos2D min = this.pos.get();
|
||||
for (Pos2D offset : this.ringIteratorList)
|
||||
{
|
||||
LodUtil.assertTrue(this._inRangeAquired(min.x + offset.x, min.y + offset.y, min));
|
||||
T t = this._getUnsafe(min.x + offset.x, min.y + offset.y);
|
||||
consumer.accept(t, new Pos2D(min.x + offset.x, min.y + offset.y));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.moveLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
Pos2D p = this.pos.get();
|
||||
Pos2D p = this.minPosRef.get();
|
||||
return this.getClass().getSimpleName() + "[" + (p.x+this.halfSize) + "," + (p.y+this.halfSize) + "] " + this.size + "*" + this.size + "[" + this.size() + "]";
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user