SimpleJavaEngine/src/main/java/speiger/src/coreengine/utils/collections/managers/dynamic/DynamicDataManager.java

216 lines
5.1 KiB
Java

package speiger.src.coreengine.utils.collections.managers.dynamic;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import speiger.src.collections.ints.collections.IntIterator;
import speiger.src.collections.ints.maps.abstracts.AbstractInt2IntMap.BasicEntry;
import speiger.src.collections.ints.maps.interfaces.Int2IntMap;
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
import speiger.src.collections.ints.misc.pairs.IntObjectPair;
import speiger.src.collections.ints.sets.IntAVLTreeSet;
import speiger.src.collections.ints.sets.IntSet;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.sets.ObjectAVLTreeSet;
import speiger.src.collections.objects.utils.ObjectLists;
import speiger.src.coreengine.utils.collections.pools.ThreadPool;
public class DynamicDataManager<T>
{
static final ThreadPool<DataSlot> SLOTS = new ThreadPool<>(1000, DataSlot::new, DataSlot::clear);
final IDynamicDataHandler<T> manager;
Int2ObjectMap<DataSlot> slots = Int2ObjectMap.builder().linkedMap();
Set<DataSlot> emptySlots = new ObjectAVLTreeSet<>();
IntSet changedSlots = new IntAVLTreeSet();
DataSlot lastSlot = null;
public DynamicDataManager(IDynamicDataHandler<T> manager)
{
this.manager = manager;
}
public boolean add(int dataIndex, T value)
{
if(slots.containsKey(dataIndex)) return false;
return add(dataIndex, manager.toBytes(value));
}
protected boolean add(int dataIndex, byte[] data)
{
if(!emptySlots.isEmpty())
{
for(Iterator<DataSlot> iter = emptySlots.iterator();iter.hasNext();)
{
DataSlot slot = iter.next();
if(slot.getFreeBytes() >= data.length)
{
slot.setData(dataIndex, data);
slots.put(dataIndex, slot);
changedSlots.add(dataIndex);
return true;
}
}
}
DataSlot next = SLOTS.get();
next.set(lastSlot, dataIndex, data);
slots.put(dataIndex, next);
changedSlots.add(dataIndex);
lastSlot = next;
return true;
}
public boolean contains(int dataIndex)
{
return slots.containsKey(dataIndex);
}
public boolean update(int dataIndex, T value)
{
DataSlot slot = slots.get(dataIndex);
if(slot != null)
{
byte[] data = manager.toBytes(value);
if(slot.getFreeBytes() >= data.length)
{
slot.setData(dataIndex, data);
changedSlots.add(dataIndex);
return true;
}
else
{
slot.setData(-1, null);
slots.remove(dataIndex);
add(dataIndex, data);
emptySlots.add(slot);
return true;
}
}
return false;
}
public Iterator<Int2IntMap.Entry> iterator(int byteOffset)
{
return new Iterator<Int2IntMap.Entry>() {
BasicEntry entry = new BasicEntry();
DataSlot current = findNextSlot(lastSlot);
@Override
public boolean hasNext()
{
return current != null;
}
DataSlot findNextSlot(DataSlot input)
{
for(input = input.previous; input != null && input.value == null;input = input.previous);
return input;
}
@Override
public Int2IntMap.Entry next()
{
if(!hasNext()) throw new IllegalStateException();
entry.set(current.dataIndex, current.byteOffset / byteOffset);
current = findNextSlot(current);
return entry;
}
};
}
public boolean remove(int dataIndex)
{
DataSlot slot = slots.remove(dataIndex);
if(slot != null)
{
slot.setData(-1, null);
emptySlots.add(slot);
return true;
}
return false;
}
protected void clearEmptySlots()
{
while(lastSlot != null && lastSlot.value == null)
{
DataSlot prev = lastSlot;
emptySlots.remove(prev);
lastSlot = prev.previous;
SLOTS.accept(prev);
}
}
public void clear()
{
slots.clear();
emptySlots.clear();
changedSlots.clear();
while(lastSlot != null)
{
DataSlot prev = lastSlot;
lastSlot = prev.previous;
SLOTS.accept(prev);
}
}
public void update()
{
int last = getEndSize();
clearEmptySlots();
if(changedSlots.isEmpty())
{
if(last != getEndSize())
{
manager.uploadBytes(ObjectLists.empty(), getEndSize());
}
return;
}
List<IntObjectPair<byte[]>> list = new ObjectArrayList<>();
while(!changedSlots.isEmpty())
{
DataSlot start = null;
DataSlot current = null;
int bytesAllocated = 0;
for(IntIterator iter = changedSlots.iterator();iter.hasNext();)
{
DataSlot slot = slots.get(iter.nextInt());
iter.remove();
if(slot == null) break;
if(current == null || current.next == slot)
{
current = slot;
if(start == null) start = slot;
bytesAllocated += slot.getUsedBytes();
continue;
}
break;
}
if(bytesAllocated <= 0) continue;
byte[] data = new byte[bytesAllocated];
int byteOffset = start.byteOffset;
bytesAllocated = 0;
while(start.byteOffset <= current.byteOffset);
{
System.arraycopy(start.value, 0, data, bytesAllocated, start.value.length);
bytesAllocated += start.getUsedBytes();
start = start.next;
}
list.add(IntObjectPair.of(byteOffset, data));
}
if(!list.isEmpty())
{
manager.uploadBytes(list, getEndSize());
}
}
private int getEndSize()
{
return lastSlot == null ? 0 : lastSlot.getNextByteOffset();
}
public int size()
{
return slots.size();
}
}