4
4
*/
5
5
package one .chartsy .collections ;
6
6
7
+ import java .util .Iterator ;
7
8
import java .util .NoSuchElementException ;
8
9
9
- public class IntArrayDeque {
10
+ /**
11
+ * A custom efficient deque (double-ended queue) implementation specialized for primitive integers.
12
+ * This implementation avoids the overhead of boxing and unboxing {@code Integer} objects,
13
+ * making it more efficient than {@code ArrayDeque<Integer>}.
14
+ *
15
+ * <p>This class provides methods to add, remove, and inspect elements at both ends of the deque.
16
+ * It uses a circular buffer internally and automatically expands its capacity when full.
17
+ *
18
+ * <p><strong>Note:</strong> This implementation is not thread-safe. If multiple threads access
19
+ * an {@code IntArrayDeque} instance concurrently, external synchronization is required.
20
+ *
21
+ * @author Mariusz Bernacki
22
+ */
23
+ public class IntArrayDeque implements Iterable <Integer > {
10
24
11
25
/**
12
- * The minimum capacity that we'll use for a newly created deque .
13
- * Must be a power of 2 .
26
+ * The minimum capacity for the internal array .
27
+ * Must be a power of two .
14
28
*/
15
29
private static final int MIN_INITIAL_CAPACITY = 8 ;
16
-
30
+
31
+ /**
32
+ * The internal array for storing elements.
33
+ */
17
34
private int [] elements ;
18
- private int head , tail ;
19
35
20
- public IntArrayDeque (int size ) {
21
- allocateElements (size );
36
+ /**
37
+ * The index of the first (head) element.
38
+ */
39
+ private int head ;
40
+
41
+ /**
42
+ * The index following the last (tail) element.
43
+ */
44
+ private int tail ;
45
+
46
+ /**
47
+ * Constructs an empty deque with the specified initial capacity.
48
+ *
49
+ * @param initialCapacity the initial capacity of the deque
50
+ * @throws IllegalArgumentException if the specified initial capacity is negative
51
+ */
52
+ public IntArrayDeque (int initialCapacity ) {
53
+ if (initialCapacity < 0 ) {
54
+ throw new IllegalArgumentException ("Initial capacity must be non-negative, but was: " + initialCapacity );
55
+ }
56
+ allocateElements (initialCapacity );
22
57
}
23
-
58
+
59
+ /**
60
+ * Allocates the internal array with a capacity that is a power of two
61
+ * and at least equal to the specified number of elements.
62
+ *
63
+ * @param numElements the required minimum capacity
64
+ */
24
65
private void allocateElements (int numElements ) {
25
66
int initialCapacity = MIN_INITIAL_CAPACITY ;
26
- // Find the best power of two to hold elements.
27
- // Tests "<=" because arrays aren't kept full.
28
- if (numElements >= initialCapacity ) {
29
- initialCapacity = numElements ;
30
- initialCapacity |= (initialCapacity >>> 1 );
31
- initialCapacity |= (initialCapacity >>> 2 );
32
- initialCapacity |= (initialCapacity >>> 4 );
33
- initialCapacity |= (initialCapacity >>> 8 );
34
- initialCapacity |= (initialCapacity >>> 16 );
35
- initialCapacity ++;
36
-
37
- if (initialCapacity < 0 ) // Too many elements, must back off
38
- initialCapacity >>>= 1 ;// Good luck allocating 2 ^ 30 elements
67
+ if (numElements > initialCapacity ) {
68
+ initialCapacity = Integer .highestOneBit (numElements );
69
+ if (initialCapacity < numElements )
70
+ initialCapacity <<= 1 ;
71
+ if (initialCapacity < 0 ) // Overflow occurred
72
+ initialCapacity >>>= 1 ;
39
73
}
40
74
elements = new int [initialCapacity ];
41
75
}
42
-
43
- public int pollLast () {
44
- if (isEmpty ())
45
- throw new NoSuchElementException ();
46
-
47
- int t = (tail - 1 ) & (elements .length - 1 );
48
- int result = elements [t ];
49
- tail = t ;
50
- return result ;
76
+
77
+ /**
78
+ * Inserts the specified element at the front of this deque.
79
+ *
80
+ * @param e the element to add
81
+ */
82
+ public void offerFirst (int e ) {
83
+ head = mask (head - 1 );
84
+ elements [head ] = e ;
85
+ if (head == tail ) {
86
+ expandCapacity ();
87
+ }
51
88
}
52
-
53
- public boolean offerLast (int e ) {
89
+
90
+ /**
91
+ * Inserts the specified element at the end of this deque.
92
+ *
93
+ * @param e the element to add
94
+ */
95
+ public void offerLast (int e ) {
54
96
elements [tail ] = e ;
55
- if ((tail = (tail + 1 ) & (elements .length - 1 )) == head )
97
+ tail = mask (tail + 1 );
98
+ if (tail == head ) {
56
99
expandCapacity ();
100
+ }
101
+ }
57
102
58
- return true ;
103
+ /**
104
+ * Retrieves and removes the first element of this deque.
105
+ *
106
+ * @return the head of this deque
107
+ * @throws NoSuchElementException if this deque is empty
108
+ */
109
+ public int pollFirst () {
110
+ if (isEmpty ()) {
111
+ throw new NoSuchElementException ("Deque is empty" );
112
+ }
113
+ int result = elements [head ];
114
+ head = mask (head + 1 );
115
+ return result ;
59
116
}
60
-
117
+
118
+ /**
119
+ * Retrieves and removes the last element of this deque.
120
+ *
121
+ * @return the tail of this deque
122
+ * @throws NoSuchElementException if this deque is empty
123
+ */
124
+ public int pollLast () {
125
+ if (isEmpty ()) {
126
+ throw new NoSuchElementException ("Deque is empty" );
127
+ }
128
+ tail = mask (tail - 1 );
129
+ return elements [tail ];
130
+ }
131
+
132
+ /**
133
+ * Retrieves, but does not remove, the first element of this deque.
134
+ *
135
+ * @return the head of this deque
136
+ * @throws NoSuchElementException if this deque is empty
137
+ */
61
138
public int getFirst () {
62
- if (isEmpty ())
63
- throw new NoSuchElementException ();
64
-
139
+ if (isEmpty ()) {
140
+ throw new NoSuchElementException ("Deque is empty" );
141
+ }
65
142
return elements [head ];
66
143
}
67
-
144
+
68
145
/**
69
- * @throws NoSuchElementException {@inheritDoc}
146
+ * Retrieves, but does not remove, the last element of this deque.
147
+ *
148
+ * @return the tail of this deque
149
+ * @throws NoSuchElementException if this deque is empty
70
150
*/
71
151
public int getLast () {
72
- if (isEmpty ())
73
- throw new NoSuchElementException ();
152
+ if (isEmpty ()) {
153
+ throw new NoSuchElementException ("Deque is empty" );
154
+ }
155
+ return elements [mask (tail - 1 )];
156
+ }
74
157
75
- return elements [(tail - 1 ) & (elements .length - 1 )];
158
+ /**
159
+ * Returns {@code true} if this deque contains no elements.
160
+ *
161
+ * @return {@code true} if this deque is empty
162
+ */
163
+ public boolean isEmpty () {
164
+ return head == tail ;
76
165
}
77
-
78
- public int pollFirst () {
79
- if (isEmpty ())
80
- throw new NoSuchElementException ();
81
-
82
- int h = head ;
83
- int result = elements [h ];
84
- head = (h + 1 ) & (elements .length - 1 );
85
- return result ;
166
+
167
+ /**
168
+ * Returns the number of elements in this deque.
169
+ *
170
+ * @return the number of elements
171
+ */
172
+ public int size () {
173
+ return (tail - head ) & (elements .length - 1 );
86
174
}
87
-
88
- public final boolean isEmpty () {
89
- return head == tail ;
175
+
176
+ /**
177
+ * Clears all elements from the deque.
178
+ * After this call, {@code isEmpty()} will return {@code true}.
179
+ */
180
+ public void clear () {
181
+ head = 0 ;
182
+ tail = 0 ;
90
183
}
91
-
184
+
185
+ /**
186
+ * Doubles the capacity of the internal array.
187
+ *
188
+ * @throws IllegalStateException if the deque is too large to expand
189
+ */
92
190
private void expandCapacity () {
93
- assert head == tail ;
94
- int p = head ;
95
- int n = elements .length ;
96
- int r = n - p ; // number of elements to the right of p
97
- int newCapacity = n << 1 ;
98
- if (newCapacity < 0 )
99
- throw new IllegalStateException ("Sorry, deque too big" );
100
-
101
- int [] a = new int [newCapacity ];
102
- System .arraycopy (elements , p , a , 0 , r );
103
- System .arraycopy (elements , 0 , a , r , p );
104
- elements = a ;
191
+ assert head == tail : "expandCapacity called when deque is not full" ;
192
+ int oldCapacity = elements .length ;
193
+ int newCapacity = oldCapacity << 1 ;
194
+ if (newCapacity < 0 ) { // Overflow
195
+ throw new IllegalStateException ("Deque too big" );
196
+ }
197
+ int [] newArray = new int [newCapacity ];
198
+ int rightElements = oldCapacity - head ;
199
+ System .arraycopy (elements , head , newArray , 0 , rightElements );
200
+ System .arraycopy (elements , 0 , newArray , rightElements , head );
201
+ elements = newArray ;
105
202
head = 0 ;
106
- tail = n ;
203
+ tail = oldCapacity ;
204
+ }
205
+
206
+ /**
207
+ * Applies bitmasking to wrap the index within the bounds of the internal array.
208
+ *
209
+ * @param index the original index
210
+ * @return the masked index
211
+ */
212
+ private int mask (int index ) {
213
+ return index & (elements .length - 1 );
214
+ }
215
+
216
+ /**
217
+ * Returns an iterator over the elements in this deque from front to back.
218
+ *
219
+ * @return an iterator over the elements in this deque
220
+ */
221
+ @ Override
222
+ public Iterator <Integer > iterator () {
223
+ return new Iterator <>() {
224
+ private int current = head ;
225
+ private int remaining = size ();
226
+
227
+ @ Override
228
+ public boolean hasNext () {
229
+ return remaining > 0 ;
230
+ }
231
+
232
+ @ Override
233
+ public Integer next () {
234
+ if (!hasNext ()) {
235
+ throw new NoSuchElementException ();
236
+ }
237
+ int result = elements [current ];
238
+ current = mask (current + 1 );
239
+ remaining --;
240
+ return result ;
241
+ }
242
+ };
107
243
}
108
- }
244
+ }
0 commit comments