2
2
3
3
import java .util .concurrent .atomic .AtomicInteger ;
4
4
5
+ /**
6
+ * The {@code CircularBuffer} class implements a generic circular (or ring) buffer.
7
+ * A circular buffer is a fixed-size data structure that operates in a FIFO (First In, First Out) manner.
8
+ * The buffer allows you to overwrite old data when the buffer is full and efficiently use limited memory.
9
+ * When the buffer is full, adding a new item will overwrite the oldest data.
10
+ *
11
+ * @param <Item> The type of elements stored in the circular buffer.
12
+ */
5
13
public class CircularBuffer <Item > {
6
14
private final Item [] buffer ;
7
15
private final CircularPointer putPointer ;
8
16
private final CircularPointer getPointer ;
9
17
private final AtomicInteger size = new AtomicInteger (0 );
10
18
19
+ /**
20
+ * Constructor to initialize the circular buffer with a specified size.
21
+ *
22
+ * @param size The size of the circular buffer.
23
+ * @throws IllegalArgumentException if the size is zero or negative.
24
+ */
11
25
public CircularBuffer (int size ) {
26
+ if (size <= 0 ) {
27
+ throw new IllegalArgumentException ("Buffer size must be positive" );
28
+ }
12
29
// noinspection unchecked
13
30
this .buffer = (Item []) new Object [size ];
14
31
this .putPointer = new CircularPointer (0 , size );
15
32
this .getPointer = new CircularPointer (0 , size );
16
33
}
17
34
35
+ /**
36
+ * Checks if the circular buffer is empty.
37
+ * This method is based on the current size of the buffer.
38
+ *
39
+ * @return {@code true} if the buffer is empty, {@code false} otherwise.
40
+ */
18
41
public boolean isEmpty () {
19
42
return size .get () == 0 ;
20
43
}
21
44
45
+ /**
46
+ * Checks if the circular buffer is full.
47
+ * The buffer is considered full when its size equals its capacity.
48
+ *
49
+ * @return {@code true} if the buffer is full, {@code false} otherwise.
50
+ */
22
51
public boolean isFull () {
23
52
return size .get () == buffer .length ;
24
53
}
25
54
55
+ /**
56
+ * Retrieves and removes the item at the front of the buffer (FIFO).
57
+ * This operation will move the {@code getPointer} forward.
58
+ *
59
+ * @return The item at the front of the buffer, or {@code null} if the buffer is empty.
60
+ */
26
61
public Item get () {
27
62
if (isEmpty ()) {
28
63
return null ;
@@ -33,31 +68,64 @@ public Item get() {
33
68
return item ;
34
69
}
35
70
71
+ /**
72
+ * Adds an item to the end of the buffer (FIFO).
73
+ * If the buffer is full, this operation will overwrite the oldest data.
74
+ *
75
+ * @param item The item to be added.
76
+ * @throws IllegalArgumentException if the item is null.
77
+ * @return {@code true} if the item was successfully added, {@code false} if the buffer was full and the item overwrote existing data.
78
+ */
36
79
public boolean put (Item item ) {
80
+ if (item == null ) {
81
+ throw new IllegalArgumentException ("Null items are not allowed" );
82
+ }
83
+
84
+ boolean wasEmpty = isEmpty ();
37
85
if (isFull ()) {
38
- return false ;
86
+ getPointer .getAndIncrement (); // Move get pointer to discard oldest item
87
+ } else {
88
+ size .incrementAndGet ();
39
89
}
40
90
41
91
buffer [putPointer .getAndIncrement ()] = item ;
42
- size .incrementAndGet ();
43
- return true ;
92
+ return wasEmpty ;
44
93
}
45
94
95
+ /**
96
+ * The {@code CircularPointer} class is a helper class used to track the current index (pointer)
97
+ * in the circular buffer.
98
+ * The max value represents the capacity of the buffer.
99
+ * The `CircularPointer` class ensures that the pointer automatically wraps around to 0
100
+ * when it reaches the maximum index.
101
+ * This is achieved in the `getAndIncrement` method, where the pointer
102
+ * is incremented and then taken modulo the maximum value (`max`).
103
+ * This operation ensures that the pointer always stays within the bounds of the buffer.
104
+ */
46
105
private static class CircularPointer {
47
106
private int pointer ;
48
107
private final int max ;
49
108
109
+ /**
110
+ * Constructor to initialize the circular pointer.
111
+ *
112
+ * @param pointer The initial position of the pointer.
113
+ * @param max The maximum size (capacity) of the circular buffer.
114
+ */
50
115
CircularPointer (int pointer , int max ) {
51
116
this .pointer = pointer ;
52
117
this .max = max ;
53
118
}
54
119
120
+ /**
121
+ * Increments the pointer by 1 and wraps it around to 0 if it reaches the maximum value.
122
+ * This ensures the pointer always stays within the buffer's bounds.
123
+ *
124
+ * @return The current pointer value before incrementing.
125
+ */
55
126
public int getAndIncrement () {
56
- if (pointer == max ) {
57
- pointer = 0 ;
58
- }
59
127
int tmp = pointer ;
60
- pointer ++ ;
128
+ pointer = ( pointer + 1 ) % max ;
61
129
return tmp ;
62
130
}
63
131
}
0 commit comments