Skip to content

Commit 35e4d96

Browse files
Rework next() hasNext() & constructors
Improved performance by the first and next position being cached (thoroughly tested) Use Slot.FIRST.copy() as a way to save some performance (copying is very fast thanks to the fast copy private constructor) Add documentation
1 parent 332f7bd commit 35e4d96

File tree

1 file changed

+98
-195
lines changed

1 file changed

+98
-195
lines changed

src/main/java/me/flame/menus/menu/iterator/MenuIterator.java

Lines changed: 98 additions & 195 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import me.flame.menus.items.MenuItem;
44
import me.flame.menus.menu.BaseMenu;
5+
import me.flame.menus.menu.IterationDirection;
56
import me.flame.menus.menu.Slot;
7+
68
import org.jetbrains.annotations.NotNull;
79
import org.jetbrains.annotations.Nullable;
810

@@ -19,239 +21,140 @@
1921
*/
2022
@SuppressWarnings("unused")
2123
public final class MenuIterator implements Iterator<MenuItem> {
22-
2324
@NotNull
24-
private Slot currentPosition;
25+
private Slot position;
2526

2627
@NotNull
2728
private final IterationDirection direction;
2829

30+
2931
@NotNull
3032
private final BaseMenu<?> menu;
3133

32-
private final int menuRows;
34+
private Slot next;
35+
36+
private boolean isFirst = true;
37+
38+
private final int rows;
39+
40+
private static final String NOTHING_MORE_NEXT =
41+
"Used PageIterator#next() but nothing more" +
42+
"\nFix: Use hasNext() beforehand to avoid this error.";
43+
44+
private static final String NOTHING_MORE_NEXT_OPTIONAL =
45+
"Used PageIterator#nextOptional() but nothing more" +
46+
"\nFix: Use hasNext() beforehand to avoid this error.";
47+
48+
private static final String NOTHING_MORE_NEXT_NOT_NULL =
49+
"Used PageIterator#nextNotNull() but nothing more";
50+
51+
private static final String GREATER_THAN_ONE_ONLY =
52+
"Starting row and column must be 1 or greater, col 9 and under or rows 6 and under only." +
53+
"\nFix: If you're using an algorithm for rows/cols, you might wanna check it";
3354

3455
public MenuIterator(int startingRow, int startingCol,
3556
@NotNull IterationDirection direction,
3657
@NotNull BaseMenu<?> menu) {
37-
if (startingRow < 1 || startingCol < 1)
38-
throw new IllegalArgumentException(
39-
"Starting row and column must be greater than 1 or equal. not under 0" +
40-
"\nFix: If you're using an algorithm for rows and/or cols, you might wanna check it."
41-
);
58+
Slot prepos = new Slot(startingRow, startingCol);
59+
if (!prepos.isSlot()) throw new IllegalArgumentException(GREATER_THAN_ONE_ONLY);
4260
this.menu = menu;
43-
this.currentPosition = new Slot(startingRow, startingCol);
61+
this.position = prepos;
4462
this.direction = direction;
45-
this.menuRows = menu.getRows();
46-
}
4763

48-
public @Nullable Slot nextSlot(boolean emptyOnly) {
49-
if (!emptyOnly) {
50-
Slot newPos = direction.shift(currentPosition, this.menuRows);
51-
currentPosition = newPos;
52-
if (!currentPosition.isSlot()) {
53-
return null;
54-
}
55-
return newPos;
56-
}
57-
58-
while (menu.hasItem(currentPosition)) {
59-
Slot shiftedPos = direction.shift(currentPosition, this.menuRows);
64+
this.rows = menu.getRows();
65+
}
66+
public MenuIterator(@NotNull IterationDirection direction,
67+
@NotNull BaseMenu<?> menu) {
68+
this.menu = menu;
69+
this.position = Slot.FIRST.copy();
70+
this.direction = direction;
6071

61-
if (!shiftedPos.isSlot()) {
62-
return null;
63-
}
72+
this.rows = menu.getRows();
73+
}
6474

65-
currentPosition = shiftedPos;
75+
/**
76+
* Retrieves the next slot in the menu.
77+
*
78+
* @param emptyOnly a boolean indicating whether to retrieve only empty slots
79+
* @return the next empty slot in the menu, or null if no empty slot is found
80+
*/
81+
public Slot nextSlot(boolean emptyOnly) {
82+
if (!emptyOnly) return nextSlot();
83+
84+
while (true) {
85+
MenuItem item = menu.getItem(position);
86+
if (item == null) break;
87+
88+
position = direction.shift(position, this.rows);
89+
if (!position.isSlot()) return null;
6690
}
6791

6892
// when it becomes empty
69-
return currentPosition;
93+
return position;
7094
}
7195

96+
/**
97+
* Retrieves the next slot in the menu.
98+
* @return the next empty slot in the menu, or null if no empty slot is found
99+
*/
72100
public @Nullable Slot nextSlot() {
73-
Slot newPos = direction.shift(currentPosition, this.menuRows);
74-
currentPosition = newPos;
75-
return !newPos.isSlot() ? null : newPos;
101+
if (!isFirst) {
102+
position = next;
103+
next = null;
104+
return position;
105+
}
106+
isFirst = false;
107+
return position;
76108
}
77109

78110
@Override
79111
public boolean hasNext() {
80-
return currentPosition.isSlot();
112+
if (next != null) return true;
113+
next = direction.shift(position, this.rows);
114+
return next.isSlot();
81115
}
82116

83117
@Override
84-
public @Nullable MenuItem next() {
118+
public MenuItem next() {
85119
Slot slot = nextSlot();
86-
if (slot == null)
87-
throw new NoSuchElementException("Used MenuIterator#next() but no more items to iterate over");
88-
return menu.getItem(slot);
120+
if (slot != null) return menu.getItem(slot.getSlot());
121+
throw new NoSuchElementException(NOTHING_MORE_NEXT);
89122
}
90123

91-
public @NotNull MenuItem nextNotNull() {
92-
// don't be fooled, this is only 1 loop through the menu, not 1 AND recursion, only one happens.
93-
Slot slot = nextSlot();
94-
if (slot == null) {
95-
while (hasNext()) {
96-
slot = nextSlot();
97-
if (slot == null) continue;
98-
MenuItem item = menu.getItem(slot);
99-
if (item != null) {
100-
return item;
101-
}
102-
}
103-
104-
throw new NoSuchElementException("Used MenuIterator#next() but no more items to iterate over");
124+
/**
125+
* Retrieves the next non-null MenuItem in the menu.
126+
*
127+
* @return the next non-null MenuItem in the menu
128+
*/
129+
public MenuItem nextNotNull() {
130+
while (hasNext()) {
131+
Slot slot = nextSlot();
132+
if (slot == null)
133+
throw new NoSuchElementException(NOTHING_MORE_NEXT_NOT_NULL +
134+
"\nFix: Everything after slot " + position.getSlot() + " is empty/null."
135+
);
136+
137+
MenuItem item = menu.getItem(slot.getSlot());
138+
if (item != null) return item;
105139
}
106140

107-
MenuItem item = menu.getItem(slot);
108-
if (item != null) {
109-
return item;
110-
}
111-
return nextNotNull();
141+
throw new NoSuchElementException(NOTHING_MORE_NEXT_NOT_NULL +
142+
"\nFix: Everything after slot " + position.getSlot() + " is empty/null."
143+
);
112144
}
113145

146+
147+
/**
148+
* Retrieves the next optional menu item.
149+
*
150+
* @return an Optional object containing the next MenuItem, if available.
151+
* Returns an empty Optional if the slot in the menu is empty.
152+
* Returns an empty Optional if there are no more items.
153+
* @throws NoSuchElementException if there are no more items in the menu.
154+
*/
114155
public Optional<MenuItem> nextOptional() {
115156
Slot slot = nextSlot();
116-
if (slot == null)
117-
throw new NoSuchElementException("Used MenuIterator#next() but no more items to iterate over");
118-
return menu.get(slot);
119-
}
120-
121-
public enum IterationDirection {
122-
HORIZONTAL() {
123-
@Override
124-
Slot shift(Slot oldPos, int maxRows) {
125-
126-
int oldCol = oldPos.getColumn();
127-
int oldRow = oldPos.getRow();
128-
129-
if (oldCol == 9 && oldRow < maxRows) {
130-
oldCol = 1;
131-
oldRow++;
132-
} else {
133-
oldCol++;
134-
}
135-
136-
return new Slot(oldRow, oldCol);
137-
}
138-
},
139-
140-
VERTICAL() {
141-
@Override
142-
Slot shift(Slot oldPos, int maxRows) {
143-
int oldCol = oldPos.getColumn();
144-
int oldRow = oldPos.getRow();
145-
146-
if (oldCol < 9 && oldRow == maxRows) {
147-
oldCol++;
148-
oldRow = 1;
149-
} else {
150-
oldRow++;
151-
}
152-
153-
return new Slot(oldRow, oldCol);
154-
}
155-
},
156-
157-
UPWARDS_ONLY {
158-
159-
@Override
160-
Slot shift(Slot oldPos, int maxRows) {
161-
int oldRow = oldPos.getRow();
162-
int row = oldRow - 1;
163-
if (row < 1) {
164-
row = oldRow;
165-
}
166-
return new Slot(row, oldPos.getColumn());
167-
}
168-
},
169-
170-
DOWNWARDS_ONLY {
171-
@Override
172-
Slot shift(Slot oldPos, int maxRows) {
173-
int oldRow = oldPos.getRow();
174-
int row = oldRow + 1;
175-
if (row > maxRows) {
176-
row = oldRow;
177-
}
178-
return new Slot(row, oldPos.getColumn());
179-
}
180-
},
181-
182-
RIGHT_ONLY {
183-
@Override
184-
Slot shift(Slot oldPos, int maxRows) {
185-
int oldCol = oldPos.getColumn() + 1;
186-
int col = oldCol > 9 ? oldCol - 1 : oldCol;
187-
return new Slot(oldPos.getRow(), col);
188-
}
189-
},
190-
191-
192-
LEFT_ONLY {
193-
@Override
194-
Slot shift(Slot oldPos, int maxRows) {
195-
int oldCol = oldPos.getColumn() - 1;
196-
int col = oldCol < 1 ? oldCol + 1 : oldCol;
197-
return new Slot(oldPos.getRow(), col);
198-
}
199-
},
200-
201-
202-
RIGHT_UPWARDS_ONLY {
203-
@Override
204-
Slot shift(Slot oldPos, int maxRows) {
205-
Slot upwardSlot = UPWARDS_ONLY.shift(oldPos, maxRows);
206-
int row = upwardSlot.getRow();
207-
208-
Slot rightSlot = RIGHT_ONLY.shift(oldPos, maxRows);
209-
int col = rightSlot.getColumn();
210-
211-
return new Slot(row, col);
212-
}
213-
},
214-
215-
216-
RIGHT_DOWNWARDS_ONLY {
217-
@Override
218-
Slot shift(Slot oldPos, int maxRows) {
219-
Slot downwardSlot = DOWNWARDS_ONLY.shift(oldPos, maxRows);
220-
int row = downwardSlot.getRow();
221-
222-
Slot rightSlot = RIGHT_ONLY.shift(oldPos, maxRows);
223-
int col = rightSlot.getColumn();
224-
225-
return new Slot(row, col);
226-
}
227-
},
228-
229-
LEFT_UPWARDS {
230-
@Override
231-
Slot shift(Slot oldPos, int maxRows) {
232-
Slot upwardSlot = UPWARDS_ONLY.shift(oldPos, maxRows);
233-
int row = upwardSlot.getRow();
234-
235-
Slot leftSlot = LEFT_ONLY.shift(oldPos, maxRows);
236-
int col = leftSlot.getColumn();
237-
238-
return new Slot(row, col);
239-
}
240-
},
241-
242-
LEFT_DOWNWARDS {
243-
@Override
244-
Slot shift(Slot oldPos, int maxRows) {
245-
Slot downwardSlot = DOWNWARDS_ONLY.shift(oldPos, maxRows);
246-
int row = downwardSlot.getRow();
247-
248-
Slot leftSlot = LEFT_ONLY.shift(oldPos, maxRows);
249-
int col = leftSlot.getColumn();
250-
251-
return new Slot(row, col);
252-
}
253-
};
254-
255-
abstract Slot shift(Slot oldPos, int maxRows);
157+
if (slot != null) return menu.get(slot);
158+
throw new NoSuchElementException(NOTHING_MORE_NEXT_OPTIONAL);
256159
}
257160
}

0 commit comments

Comments
 (0)