Skip to content

Commit 161b040

Browse files
committed
Optimize batch insert and extracts for component backed handlers
1 parent 169e041 commit 161b040

File tree

9 files changed

+154
-56
lines changed

9 files changed

+154
-56
lines changed

src/api/java/mekanism/api/chemical/ChemicalUtils.java

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,29 @@ public static <CHEMICAL extends Chemical<CHEMICAL>, STACK extends ChemicalStack<
7878
//Short circuit if nothing is actually being inserted
7979
return empty;
8080
}
81-
List<TANK> chemicalContainers = tankSupplier.apply(side);
82-
if (chemicalContainers.isEmpty()) {
81+
List<TANK> chemicalTanks = tankSupplier.apply(side);
82+
return insert(stack, action, automationType, empty, chemicalTanks.size(), chemicalTanks);
83+
}
84+
85+
/**
86+
* Util method for a generic insert implementation for various handlers. Mainly for internal use only
87+
*
88+
* @since 10.6.0
89+
*/
90+
public static <CHEMICAL extends Chemical<CHEMICAL>, STACK extends ChemicalStack<CHEMICAL>, TANK extends IChemicalTank<CHEMICAL, STACK>> STACK insert(STACK stack,
91+
Action action, AutomationType automationType, STACK empty, int size, Iterable<TANK> chemicalTanks) {
92+
if (stack.isEmpty()) {
93+
//Short circuit if nothing is actually being inserted
94+
return empty;
95+
} else if (size == 0) {
8396
return stack;
84-
} else if (chemicalContainers.size() == 1) {
85-
return chemicalContainers.getFirst().insert(stack, action, automationType);
97+
} else if (size == 1) {
98+
return chemicalTanks.iterator().next().insert(stack, action, automationType);
8699
}
87100
STACK toInsert = stack;
88101
//Start by trying to insert into the tanks that have the same type
89102
List<TANK> emptyTanks = new ArrayList<>();
90-
for (TANK tank : chemicalContainers) {
103+
for (TANK tank : chemicalTanks) {
91104
if (tank.isEmpty()) {
92105
emptyTanks.add(tank);
93106
} else if (tank.isTypeEqual(stack)) {
@@ -165,10 +178,20 @@ public static <CHEMICAL extends Chemical<CHEMICAL>, STACK extends ChemicalStack<
165178
return empty;
166179
}
167180
List<TANK> chemicalTanks = tankSupplier.apply(side);
168-
if (chemicalTanks.isEmpty()) {
181+
return extract(amount, action, automationType, empty, chemicalTanks.size(), chemicalTanks);
182+
}
183+
184+
/**
185+
* Util method for a generic extraction implementation for various handlers. Mainly for internal use only
186+
*
187+
* @since 10.6.0
188+
*/
189+
public static <CHEMICAL extends Chemical<CHEMICAL>, STACK extends ChemicalStack<CHEMICAL>, TANK extends IChemicalTank<CHEMICAL, STACK>> STACK extract(long amount,
190+
Action action, AutomationType automationType, STACK empty, int size, Iterable<TANK> chemicalTanks) {
191+
if (amount == 0 || size == 0) {
169192
return empty;
170-
} else if (chemicalTanks.size() == 1) {
171-
return chemicalTanks.getFirst().extract(amount, action, automationType);
193+
} else if (size == 1) {
194+
return chemicalTanks.iterator().next().extract(amount, action, automationType);
172195
}
173196
STACK extracted = empty;
174197
long toDrain = amount;
@@ -252,10 +275,20 @@ public static <CHEMICAL extends Chemical<CHEMICAL>, STACK extends ChemicalStack<
252275
return empty;
253276
}
254277
List<TANK> chemicalTanks = tankSupplier.apply(side);
255-
if (chemicalTanks.isEmpty()) {
278+
return extract(stack, action, automationType, empty, chemicalTanks.size(), chemicalTanks);
279+
}
280+
281+
/**
282+
* Util method for a generic extraction implementation for various handlers. Mainly for internal use only
283+
*
284+
* @since 10.6.0
285+
*/
286+
public static <CHEMICAL extends Chemical<CHEMICAL>, STACK extends ChemicalStack<CHEMICAL>, TANK extends IChemicalTank<CHEMICAL, STACK>> STACK extract(STACK stack,
287+
Action action, AutomationType automationType, STACK empty, int size, Iterable<TANK> chemicalTanks) {
288+
if (stack.isEmpty() || size == 0) {
256289
return empty;
257-
} else if (chemicalTanks.size() == 1) {
258-
TANK tank = chemicalTanks.getFirst();
290+
} else if (size == 1) {
291+
TANK tank = chemicalTanks.iterator().next();
259292
if (tank.isEmpty() || !tank.isTypeEqual(stack)) {
260293
return empty;
261294
}

src/api/java/mekanism/api/fluid/ExtendedFluidHandlerUtils.java

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -74,16 +74,28 @@ public static FluidStack insert(FluidStack stack, @Nullable Direction side, Func
7474
//Short circuit if nothing is actually being inserted
7575
return FluidStack.EMPTY;
7676
}
77-
List<IExtendedFluidTank> fluidContainers = fluidTankSupplier.apply(side);
78-
if (fluidContainers.isEmpty()) {
77+
List<IExtendedFluidTank> fluidTanks = fluidTankSupplier.apply(side);
78+
return insert(stack, action, automationType, fluidTanks.size(), fluidTanks);
79+
}
80+
81+
/**
82+
* Util method for a generic insert implementation for various handlers. Mainly for internal use only
83+
*
84+
* @since 10.6.0
85+
*/
86+
public static FluidStack insert(FluidStack stack, Action action, AutomationType automationType, int size, Iterable<IExtendedFluidTank> fluidTanks) {
87+
if (stack.isEmpty()) {
88+
//Short circuit if nothing is actually being inserted
89+
return FluidStack.EMPTY;
90+
} else if (size == 0) {
7991
return stack;
80-
} else if (fluidContainers.size() == 1) {
81-
return fluidContainers.getFirst().insert(stack, action, automationType);
92+
} else if (size == 1) {
93+
return fluidTanks.iterator().next().insert(stack, action, automationType);
8294
}
8395
FluidStack toInsert = stack;
8496
//Start by trying to insert into the tanks that have the same type
8597
List<IExtendedFluidTank> emptyTanks = new ArrayList<>();
86-
for (IExtendedFluidTank tank : fluidContainers) {
98+
for (IExtendedFluidTank tank : fluidTanks) {
8799
if (tank.isEmpty()) {
88100
emptyTanks.add(tank);
89101
} else if (tank.isFluidEqual(stack)) {
@@ -160,15 +172,24 @@ public static FluidStack extract(int amount, @Nullable Direction side, Function<
160172
if (amount == 0) {
161173
return FluidStack.EMPTY;
162174
}
163-
List<IExtendedFluidTank> fluidContainers = fluidTankSupplier.apply(side);
164-
if (fluidContainers.isEmpty()) {
175+
List<IExtendedFluidTank> fluidTanks = fluidTankSupplier.apply(side);
176+
return extract(amount, action, automationType, fluidTanks.size(), fluidTanks);
177+
}
178+
179+
/**
180+
* Util method for a generic extraction implementation for various handlers. Mainly for internal use only
181+
*
182+
* @since 10.6.0
183+
*/
184+
public static FluidStack extract(int amount, Action action, AutomationType automationType, int size, Iterable<IExtendedFluidTank> fluidTanks) {
185+
if (amount == 0 || size == 0) {
165186
return FluidStack.EMPTY;
166-
} else if (fluidContainers.size() == 1) {
167-
return fluidContainers.getFirst().extract(amount, action, automationType);
187+
} else if (size == 1) {
188+
return fluidTanks.iterator().next().extract(amount, action, automationType);
168189
}
169190
FluidStack extracted = FluidStack.EMPTY;
170191
int toDrain = amount;
171-
for (IExtendedFluidTank fluidTank : fluidContainers) {
192+
for (IExtendedFluidTank fluidTank : fluidTanks) {
172193
if (extracted.isEmpty() || fluidTank.isFluidEqual(extracted)) {
173194
//If there is fluid in the tank that matches the type we have started draining, or we haven't found a type yet
174195
FluidStack drained = fluidTank.extract(toDrain, action, automationType);
@@ -247,19 +268,28 @@ public static FluidStack extract(FluidStack stack, @Nullable Direction side, Fun
247268
if (stack.isEmpty()) {
248269
return FluidStack.EMPTY;
249270
}
250-
List<IExtendedFluidTank> fluidContainers = fluidTankSupplier.apply(side);
251-
if (fluidContainers.isEmpty()) {
271+
List<IExtendedFluidTank> fluidTanks = fluidTankSupplier.apply(side);
272+
return extract(stack, action, automationType, fluidTanks.size(), fluidTanks);
273+
}
274+
275+
/**
276+
* Util method for a generic extraction implementation for various handlers. Mainly for internal use only
277+
*
278+
* @since 10.6.0
279+
*/
280+
public static FluidStack extract(FluidStack stack, Action action, AutomationType automationType, int size, Iterable<IExtendedFluidTank> fluidTanks) {
281+
if (stack.isEmpty() || size == 0) {
252282
return FluidStack.EMPTY;
253-
} else if (fluidContainers.size() == 1) {
254-
IExtendedFluidTank tank = fluidContainers.getFirst();
283+
} else if (size == 1) {
284+
IExtendedFluidTank tank = fluidTanks.iterator().next();
255285
if (tank.isEmpty() || !tank.isFluidEqual(stack)) {
256286
return FluidStack.EMPTY;
257287
}
258288
return tank.extract(stack.getAmount(), action, automationType);
259289
}
260290
FluidStack extracted = FluidStack.EMPTY;
261291
int toDrain = stack.getAmount();
262-
for (IExtendedFluidTank fluidTank : fluidContainers) {
292+
for (IExtendedFluidTank fluidTank : fluidTanks) {
263293
if (fluidTank.isFluidEqual(stack)) {
264294
//If there is fluid in the tank that matches the type we are trying to drain, try to drain from it
265295
FluidStack drained = fluidTank.extract(toDrain, action, automationType);

src/api/java/mekanism/api/math/FloatingLongTransferUtils.java

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,22 @@ public static FloatingLong insert(FloatingLong stack, @Nullable Direction side,
7979
return FloatingLong.ZERO;
8080
}
8181
List<IEnergyContainer> energyContainers = energyContainerSupplier.apply(side);
82-
if (energyContainers.isEmpty()) {
82+
return insert(stack, action, automationType, energyContainers.size(), energyContainers);
83+
}
84+
85+
/**
86+
* Util method for a generic insert implementation for various handlers. Mainly for internal use only
87+
*
88+
* @since 10.6.0
89+
*/
90+
public static FloatingLong insert(FloatingLong stack, Action action, AutomationType automationType, int size, Iterable<IEnergyContainer> energyContainers) {
91+
if (stack.isZero()) {
92+
//Short circuit if no energy is trying to be inserted
93+
return FloatingLong.ZERO;
94+
} else if (size == 0) {
8395
return stack;
84-
} else if (energyContainers.size() == 1) {
85-
return energyContainers.getFirst().insert(stack, action, automationType);
96+
} else if (size == 1) {
97+
return energyContainers.iterator().next().insert(stack, action, automationType);
8698
}
8799
FloatingLong toInsert = stack;
88100
//Start by trying to insert into the containers that are not empty
@@ -164,10 +176,20 @@ public static FloatingLong extract(FloatingLong amount, @Nullable Direction side
164176
return FloatingLong.ZERO;
165177
}
166178
List<IEnergyContainer> energyContainers = energyContainerSupplier.apply(side);
167-
if (energyContainers.isEmpty()) {
179+
return extract(amount, action, automationType, energyContainers.size(), energyContainers);
180+
}
181+
182+
/**
183+
* Util method for a generic extraction implementation for various handlers. Mainly for internal use only
184+
*
185+
* @since 10.6.0
186+
*/
187+
public static FloatingLong extract(FloatingLong amount, Action action, AutomationType automationType, int size, Iterable<IEnergyContainer> energyContainers) {
188+
if (amount.isZero() || size == 0) {
189+
//Short circuit if no energy is trying to be extracted
168190
return FloatingLong.ZERO;
169-
} else if (energyContainers.size() == 1) {
170-
return energyContainers.getFirst().extract(amount, action, automationType);
191+
} else if (size == 1) {
192+
return energyContainers.iterator().next().extract(amount, action, automationType);
171193
}
172194
FloatingLong extracted = FloatingLong.ZERO;
173195
FloatingLong toExtract = amount.copy();

src/main/java/mekanism/common/attachments/containers/ComponentBackedHandler.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package mekanism.common.attachments.containers;
22

33
import java.util.Arrays;
4+
import java.util.Iterator;
45
import java.util.List;
56
import mekanism.api.IContentsListener;
67
import mekanism.api.annotations.NothingNullByDefault;
@@ -11,7 +12,7 @@
1112

1213
@NothingNullByDefault
1314
public abstract class ComponentBackedHandler<TYPE, CONTAINER extends INBTSerializable<CompoundTag>, ATTACHED extends IAttachedContainers<TYPE, ATTACHED>>
14-
implements IContentsListener {
15+
implements IContentsListener, Iterable<CONTAINER> {
1516

1617
protected final ItemStack attachedTo;
1718
private final int totalContainers;
@@ -71,11 +72,31 @@ protected CONTAINER getContainer(int index) {
7172
return container == null ? initializeContainer(index) : container;
7273
}
7374

74-
protected int containerCount() {
75+
protected int size() {
7576
return totalContainers;
7677
}
7778

7879
@Override
7980
public void onContentsChanged() {
8081
}
82+
83+
@Override
84+
public Iterator<CONTAINER> iterator() {
85+
return new ContainerIterator();
86+
}
87+
88+
private class ContainerIterator implements Iterator<CONTAINER> {
89+
90+
private int cursor = 0;
91+
92+
@Override
93+
public boolean hasNext() {
94+
return cursor != size();
95+
}
96+
97+
@Override
98+
public CONTAINER next() {
99+
return getContainer(cursor++);
100+
}
101+
}
81102
}

src/main/java/mekanism/common/attachments/containers/chemical/ComponentBackedChemicalHandler.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public TANK getChemicalTank(int tank, @Nullable Direction side) {
3737

3838
@Override
3939
public int getTanks(@Nullable Direction side) {
40-
return containerCount();
40+
return size();
4141
}
4242

4343
@Override
@@ -47,19 +47,16 @@ public STACK getChemicalInTank(int tank, @Nullable Direction side) {
4747

4848
@Override
4949
public STACK insertChemical(STACK stack, @Nullable Direction side, Action action) {
50-
//TODO - 1.20.5: Can we optimize this any further? Maybe by somehow only initializing the chemical tanks as necessary/we actually get to iterating against them?
51-
return ChemicalUtils.insert(stack, side, this::getChemicalTanks, action, AutomationType.handler(side), getEmptyStack());
50+
return ChemicalUtils.insert(stack, action, AutomationType.handler(side), getEmptyStack(), size(), this);
5251
}
5352

5453
@Override
5554
public STACK extractChemical(long amount, @Nullable Direction side, Action action) {
56-
//TODO - 1.20.5: Can we optimize this any further? Maybe by somehow only initializing the chemical tanks as necessary/we actually get to iterating against them?
57-
return ChemicalUtils.extract(amount, side, this::getChemicalTanks, action, AutomationType.handler(side), getEmptyStack());
55+
return ChemicalUtils.extract(amount, action, AutomationType.handler(side), getEmptyStack(), size(), this);
5856
}
5957

6058
@Override
6159
public STACK extractChemical(STACK stack, @Nullable Direction side, Action action) {
62-
//TODO - 1.20.5: Can we optimize this any further? Maybe by somehow only initializing the chemical tanks as necessary/we actually get to iterating against them?
63-
return ChemicalUtils.extract(stack, side, this::getChemicalTanks, action, AutomationType.handler(side), getEmptyStack());
60+
return ChemicalUtils.extract(stack, action, AutomationType.handler(side), getEmptyStack(), size(), this);
6461
}
6562
}

src/main/java/mekanism/common/attachments/containers/energy/ComponentBackedEnergyHandler.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public IEnergyContainer getEnergyContainer(int container, @Nullable Direction si
3939

4040
@Override
4141
public int getEnergyContainerCount(@Nullable Direction side) {
42-
return containerCount();
42+
return size();
4343
}
4444

4545
@Override
@@ -49,13 +49,11 @@ public FloatingLong getEnergy(int container, @Nullable Direction side) {
4949

5050
@Override
5151
public FloatingLong insertEnergy(FloatingLong amount, @Nullable Direction side, Action action) {
52-
//TODO - 1.20.5: Can we optimize this any further? Maybe by somehow only initializing the energy containers as necessary/we actually get to iterating against them?
53-
return FloatingLongTransferUtils.insert(amount, side, this::getEnergyContainers, action, AutomationType.handler(side));
52+
return FloatingLongTransferUtils.insert(amount, action, AutomationType.handler(side), size(), this);
5453
}
5554

5655
@Override
5756
public FloatingLong extractEnergy(FloatingLong amount, @Nullable Direction side, Action action) {
58-
//TODO - 1.20.5: Can we optimize this any further? Maybe by somehow only initializing the energy containers as necessary/we actually get to iterating against them?
59-
return FloatingLongTransferUtils.extract(amount, side, this::getEnergyContainers, action, AutomationType.handler(side));
57+
return FloatingLongTransferUtils.extract(amount, action, AutomationType.handler(side), size(), this);
6058
}
6159
}

src/main/java/mekanism/common/attachments/containers/fluid/ComponentBackedFluidHandler.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public IExtendedFluidTank getFluidTank(int tank, @Nullable Direction side) {
4040

4141
@Override
4242
public int getTanks(@Nullable Direction side) {
43-
return containerCount();
43+
return size();
4444
}
4545

4646
@Override
@@ -50,20 +50,17 @@ public FluidStack getFluidInTank(int tank, @Nullable Direction side) {
5050

5151
@Override
5252
public FluidStack insertFluid(FluidStack stack, @Nullable Direction side, Action action) {
53-
//TODO - 1.20.5: Can we optimize this any further? Maybe by somehow only initializing the fluid tanks as necessary/we actually get to iterating against them?
54-
return ExtendedFluidHandlerUtils.insert(stack, side, this::getFluidTanks, action, AutomationType.handler(side));
53+
return ExtendedFluidHandlerUtils.insert(stack, action, AutomationType.handler(side), size(), this);
5554
}
5655

5756
@Override
5857
public FluidStack extractFluid(int amount, @Nullable Direction side, Action action) {
59-
//TODO - 1.20.5: Can we optimize this any further? Maybe by somehow only initializing the fluid tanks as necessary/we actually get to iterating against them?
60-
return ExtendedFluidHandlerUtils.extract(amount, side, this::getFluidTanks, action, AutomationType.handler(side));
58+
return ExtendedFluidHandlerUtils.extract(amount, action, AutomationType.handler(side), size(), this);
6159
}
6260

6361
@Override
6462
public FluidStack extractFluid(FluidStack stack, @Nullable Direction side, Action action) {
65-
//TODO - 1.20.5: Can we optimize this any further? Maybe by somehow only initializing the fluid tanks as necessary/we actually get to iterating against them?
66-
return ExtendedFluidHandlerUtils.extract(stack, side, this::getFluidTanks, action, AutomationType.handler(side));
63+
return ExtendedFluidHandlerUtils.extract(stack, action, AutomationType.handler(side), size(), this);
6764
}
6865

6966
@Override

src/main/java/mekanism/common/attachments/containers/heat/ComponentBackedHeatHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public ComponentBackedHeatHandler(ItemStack attachedTo, int totalCapacitors) {
2424

2525
@Override
2626
public int getHeatCapacitorCount(@Nullable Direction side) {
27-
return containerCount();
27+
return size();
2828
}
2929

3030
@Override
@@ -42,7 +42,7 @@ public IHeatCapacitor getHeatCapacitor(int capacitor, @Nullable Direction side)
4242
protected HeatCapacitorData getContents(int index) {
4343
AttachedHeat attached = getAttached();
4444
if (index < 0 || index >= attached.size()) {
45-
if (index > 0 && index < containerCount()) {
45+
if (index > 0 && index < size()) {
4646
//Get the default. This isn't the cleanest way to look it up, but as we never use this method for component backed heat handlers
4747
// it should be fine for now
4848
return containerType().createNewAttachment(attachedTo).get(index);

0 commit comments

Comments
 (0)