Skip to content

Commit f4e7884

Browse files
committed
improve constructor
add methods to simplify handler logic improve handler list adding improve get add immutable handler list improve handler list tests
1 parent 99f8737 commit f4e7884

File tree

2 files changed

+135
-41
lines changed

2 files changed

+135
-41
lines changed

src/main/java/gregtech/api/capability/impl/ItemHandlerList.java

Lines changed: 95 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
99
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
1010
import it.unimi.dsi.fastutil.objects.Object2IntMap;
11-
import it.unimi.dsi.fastutil.objects.ObjectIterator;
1211
import org.jetbrains.annotations.NotNull;
1312

1413
import java.util.*;
@@ -18,22 +17,45 @@
1817
*/
1918
public class ItemHandlerList extends AbstractList<IItemHandler> implements IItemHandlerModifiable {
2019

21-
private final Int2ObjectMap<IItemHandler> handlerBySlotIndex = new Int2ObjectOpenHashMap<>();
22-
private final Object2IntMap<IItemHandler> baseIndexOffset = new Object2IntArrayMap<>();
20+
protected final Int2ObjectMap<IItemHandler> handlerBySlotIndex = new Int2ObjectOpenHashMap<>();
21+
protected final Object2IntMap<IItemHandler> baseIndexOffset = new Object2IntArrayMap<>();
2322

24-
public ItemHandlerList() {}
23+
// this is only used for get()
24+
protected IItemHandler[] handlers = new IItemHandler[0];
2525

2626
public ItemHandlerList(Collection<? extends IItemHandler> itemHandlerList) {
2727
addAll(itemHandlerList);
28+
baseIndexOffset.defaultReturnValue(-1);
29+
}
30+
31+
public ItemHandlerList() {
32+
this(Collections.emptyList());
2833
}
2934

3035
public ItemHandlerList(ItemHandlerList parent, IItemHandler... additional) {
31-
addAll(parent.getBackingHandlers());
36+
this(parent);
3237
Collections.addAll(this, additional);
3338
}
3439

40+
/**
41+
* @param handler the handler to get the slot offset of
42+
* @return the slot offset
43+
* @throws IllegalArgumentException if the handler is not in this list
44+
*/
3545
public int getIndexOffset(IItemHandler handler) {
36-
return baseIndexOffset.getOrDefault(handler, -1);
46+
int offset = baseIndexOffset.get(handler);
47+
if (offset == -1) throw new IllegalArgumentException();
48+
return offset;
49+
}
50+
51+
@NotNull
52+
protected IItemHandler getHandlerBySlot(int slot) {
53+
if (invalidSlot(slot)) throw new IndexOutOfBoundsException();
54+
return handlerBySlotIndex.get(slot);
55+
}
56+
57+
protected int getInternalSlot(int slot) {
58+
return slot - getIndexOffset(getHandlerBySlot(slot));
3759
}
3860

3961
@Override
@@ -44,11 +66,12 @@ public int getSlots() {
4466
@Override
4567
public void setStackInSlot(int slot, @NotNull ItemStack stack) {
4668
if (invalidSlot(slot)) return;
47-
IItemHandler itemHandler = handlerBySlotIndex.get(slot);
48-
int actualSlot = slot - baseIndexOffset.get(itemHandler);
69+
IItemHandler itemHandler = getHandlerBySlot(slot);
70+
int actualSlot = getInternalSlot(slot);
4971
if (itemHandler instanceof IItemHandlerModifiable modifiable) {
5072
modifiable.setStackInSlot(actualSlot, stack);
5173
} else {
74+
// should this no-op instead?
5275
itemHandler.extractItem(actualSlot, Integer.MAX_VALUE, false);
5376
itemHandler.insertItem(actualSlot, stack, false);
5477
}
@@ -58,36 +81,27 @@ public void setStackInSlot(int slot, @NotNull ItemStack stack) {
5881
@Override
5982
public ItemStack getStackInSlot(int slot) {
6083
if (invalidSlot(slot)) return ItemStack.EMPTY;
61-
IItemHandler itemHandler = handlerBySlotIndex.get(slot);
62-
return itemHandler.getStackInSlot(slot - baseIndexOffset.getInt(itemHandler));
84+
return getHandlerBySlot(slot).getStackInSlot(getInternalSlot(slot));
6385
}
6486

6587
@Override
6688
public int getSlotLimit(int slot) {
6789
if (invalidSlot(slot)) return 0;
68-
IItemHandler itemHandler = handlerBySlotIndex.get(slot);
69-
return itemHandler.getSlotLimit(slot - baseIndexOffset.getInt(itemHandler));
90+
return getHandlerBySlot(slot).getSlotLimit(getInternalSlot(slot));
7091
}
7192

7293
@NotNull
7394
@Override
7495
public ItemStack insertItem(int slot, @NotNull ItemStack stack, boolean simulate) {
7596
if (invalidSlot(slot)) return stack;
76-
IItemHandler itemHandler = handlerBySlotIndex.get(slot);
77-
return itemHandler.insertItem(slot - baseIndexOffset.getInt(itemHandler), stack, simulate);
97+
return getHandlerBySlot(slot).insertItem(getInternalSlot(slot), stack, simulate);
7898
}
7999

80100
@NotNull
81101
@Override
82102
public ItemStack extractItem(int slot, int amount, boolean simulate) {
83103
if (invalidSlot(slot)) return ItemStack.EMPTY;
84-
IItemHandler itemHandler = handlerBySlotIndex.get(slot);
85-
return itemHandler.extractItem(slot - baseIndexOffset.getInt(itemHandler), amount, simulate);
86-
}
87-
88-
private boolean invalidSlot(int slot) {
89-
if (handlerBySlotIndex.isEmpty()) return false;
90-
return slot < 0 || slot >= handlerBySlotIndex.size();
104+
return getHandlerBySlot(slot).extractItem(getInternalSlot(slot), amount, simulate);
91105
}
92106

93107
@NotNull
@@ -103,7 +117,13 @@ public int size() {
103117
@Override
104118
public boolean add(IItemHandler handler) {
105119
int s = size();
106-
add(s, handler);
120+
if (handler instanceof ItemHandlerList list) {
121+
// possible infinite recursion
122+
// throw instead?
123+
addAll(s, list);
124+
} else {
125+
add(s, handler);
126+
}
107127
return s != size();
108128
}
109129

@@ -113,12 +133,6 @@ public void add(int unused, IItemHandler element) {
113133
if (baseIndexOffset.containsKey(element)) {
114134
throw new IllegalArgumentException("Attempted to add item handler " + element + " twice");
115135
}
116-
if (element instanceof ItemHandlerList list) {
117-
// possible infinite recursion
118-
// throw instead?
119-
addAll(list);
120-
return;
121-
}
122136

123137
int offset = handlerBySlotIndex.size();
124138
baseIndexOffset.put(element, offset);
@@ -127,12 +141,16 @@ public void add(int unused, IItemHandler element) {
127141
}
128142
}
129143

144+
@Override
145+
public @NotNull Iterator<IItemHandler> iterator() {
146+
return baseIndexOffset.keySet().iterator();
147+
}
148+
130149
@Override
131150
public IItemHandler get(int index) {
132151
if (invalidIndex(index)) throw new IndexOutOfBoundsException();
133-
ObjectIterator<IItemHandler> itr = baseIndexOffset.keySet().iterator();
134-
itr.skip(index); // skip n-1 elements
135-
return itr.next(); // get nth element
152+
updateHandlerArray();
153+
return handlers[index];
136154
}
137155

138156
@Override
@@ -169,8 +187,53 @@ public IItemHandler remove(int index) {
169187
return handler;
170188
}
171189

172-
public boolean invalidIndex(int index) {
190+
private boolean invalidSlot(int slot) {
191+
if (handlerBySlotIndex.isEmpty()) return false;
192+
return slot < 0 || slot >= handlerBySlotIndex.size();
193+
}
194+
195+
private boolean invalidIndex(int index) {
173196
if (baseIndexOffset.isEmpty()) return false;
174197
return index < 0 || index >= baseIndexOffset.size();
175198
}
199+
200+
private void updateHandlerArray() {
201+
if (handlers.length != size()) {
202+
handlers = new IItemHandler[size()];
203+
int i = 0;
204+
for (IItemHandler h : baseIndexOffset.keySet()) {
205+
handlers[i++] = h;
206+
}
207+
}
208+
}
209+
210+
public ItemHandlerList toImmutable() {
211+
return new Immutable(this);
212+
}
213+
214+
private static class Immutable extends ItemHandlerList {
215+
216+
private Immutable(ItemHandlerList list) {
217+
this.handlers = list.handlers;
218+
this.baseIndexOffset.putAll(list.baseIndexOffset);
219+
this.handlerBySlotIndex.putAll(list.handlerBySlotIndex);
220+
}
221+
222+
@Override
223+
public void add(int unused, IItemHandler element) {
224+
// no op?
225+
throw new UnsupportedOperationException();
226+
}
227+
228+
@Override
229+
public IItemHandler remove(int index) {
230+
// no op?
231+
throw new UnsupportedOperationException();
232+
}
233+
234+
@Override
235+
public IItemHandler get(int index) {
236+
return handlers[index];
237+
}
238+
}
176239
}

src/test/java/gregtech/api/capability/impl/ItemHandlerListTest.java

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
import net.minecraftforge.items.IItemHandler;
66
import net.minecraftforge.items.ItemStackHandler;
77

8-
import org.hamcrest.MatcherAssert;
98
import org.junit.jupiter.api.BeforeAll;
109
import org.junit.jupiter.api.Test;
1110

1211
import java.util.Objects;
1312

13+
import static org.hamcrest.MatcherAssert.assertThat;
14+
1415
public class ItemHandlerListTest {
1516

1617
@BeforeAll
@@ -26,18 +27,48 @@ public void testListOperations() {
2627

2728
// test add
2829
list.add(firstHandler);
29-
MatcherAssert.assertThat("wrong number of slots!", list.getSlots() == 16);
30-
MatcherAssert.assertThat("wrong number of handlers!", list.size() == 1);
30+
assertThat("wrong number of slots!", list.getSlots() == 16);
31+
assertThat("wrong number of handlers!", list.size() == 1);
3132
list.add(secondHandler);
32-
MatcherAssert.assertThat("wrong number of slots!", list.getSlots() == 32);
33-
MatcherAssert.assertThat("wrong number of handlers!", list.size() == 2);
33+
assertThat("wrong number of slots!", list.getSlots() == 32);
34+
assertThat("wrong number of handlers!", list.size() == 2);
3435

3536
// test removal
3637
IItemHandler removed = list.remove(0);
37-
MatcherAssert.assertThat("wrong number of slots!", list.getSlots() == 16);
38-
MatcherAssert.assertThat("wrong number of handlers!", list.size() == 1);
39-
MatcherAssert.assertThat("removed handler is not the first handler!", Objects.equals(removed, firstHandler));
38+
assertThat("wrong number of slots!", list.getSlots() == 16);
39+
assertThat("wrong number of handlers!", list.size() == 1);
40+
assertThat("removed handler is not the first handler!", Objects.equals(removed, firstHandler));
4041
int newIndex = list.getIndexOffset(secondHandler);
41-
MatcherAssert.assertThat("second handler was not updated!", newIndex == 0);
42+
assertThat("second handler was not updated!", newIndex == 0);
43+
44+
IItemHandler get = list.get(0);
45+
assertThat("Second handler is not first!", get == secondHandler);
46+
47+
// test add after removal
48+
list.add(firstHandler);
49+
50+
get = list.get(1);
51+
assertThat("First handler is not second!", get == firstHandler);
52+
assertThat("wrong number of slots!", list.getSlots() == 32);
53+
assertThat("wrong number of handlers!", list.size() == 2);
54+
55+
// test immutable
56+
ItemHandlerList immutable = list.toImmutable();
57+
58+
boolean testRemove = false;
59+
try {
60+
immutable.remove(0);
61+
} catch (UnsupportedOperationException ignored) {
62+
testRemove = true;
63+
}
64+
assertThat("list was modified!", testRemove);
65+
66+
boolean testAdd = false;
67+
try {
68+
immutable.add(firstHandler);
69+
} catch (UnsupportedOperationException ignored) {
70+
testAdd = true;
71+
}
72+
assertThat("list was modified!", testAdd);
4273
}
4374
}

0 commit comments

Comments
 (0)