Skip to content

Commit 2b07326

Browse files
committed
Synchronize code repos
Notable changes include: - Time Representation: Shifting from microsecond to nanosecond precision for timestamps enhances accuracy and aligns with modern timekeeping practices. - Candle Data: Adding turnover and trades to the Candle interface provides a more comprehensive representation of price bars. - Financial Indicators: Refactoring and introducing new indicators like FramaTrendWhispers and AverageTrueRange expands the analytical capabilities. - Performance Optimization: Utilizing optimized parsing techniques like JavaDoubleParser and FromString enhances data processing speed. - Code Structure: Refactoring classes and interfaces, such as introducing IdentityType and InstrumentType, improves code organization and clarity. - New Features: Introducing concepts like MarketMessageSource and AlgorithmWorker lays the groundwork for more sophisticated trading simulations.
1 parent 5aa5904 commit 2b07326

File tree

4 files changed

+522
-80
lines changed

4 files changed

+522
-80
lines changed

chartsy-core/src/main/java/one/chartsy/collections/IntArrayDeque.java

Lines changed: 206 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -4,105 +4,241 @@
44
*/
55
package one.chartsy.collections;
66

7+
import java.util.Iterator;
78
import java.util.NoSuchElementException;
89

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> {
1024

1125
/**
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.
1428
*/
1529
private static final int MIN_INITIAL_CAPACITY = 8;
16-
30+
31+
/**
32+
* The internal array for storing elements.
33+
*/
1734
private int[] elements;
18-
private int head, tail;
1935

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);
2257
}
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+
*/
2465
private void allocateElements(int numElements) {
2566
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;
3973
}
4074
elements = new int[initialCapacity];
4175
}
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+
}
5188
}
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) {
5496
elements[tail] = e;
55-
if ((tail = (tail + 1) & (elements.length - 1)) == head)
97+
tail = mask(tail + 1);
98+
if (tail == head) {
5699
expandCapacity();
100+
}
101+
}
57102

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;
59116
}
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+
*/
61138
public int getFirst() {
62-
if (isEmpty())
63-
throw new NoSuchElementException();
64-
139+
if (isEmpty()) {
140+
throw new NoSuchElementException("Deque is empty");
141+
}
65142
return elements[head];
66143
}
67-
144+
68145
/**
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
70150
*/
71151
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+
}
74157

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;
76165
}
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);
86174
}
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;
90183
}
91-
184+
185+
/**
186+
* Doubles the capacity of the internal array.
187+
*
188+
* @throws IllegalStateException if the deque is too large to expand
189+
*/
92190
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;
105202
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+
};
107243
}
108-
}
244+
}

0 commit comments

Comments
 (0)