22
33import java .util .concurrent .atomic .AtomicInteger ;
44
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+ */
513public class CircularBuffer <Item > {
614 private final Item [] buffer ;
715 private final CircularPointer putPointer ;
816 private final CircularPointer getPointer ;
917 private final AtomicInteger size = new AtomicInteger (0 );
1018
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+ */
1125 public CircularBuffer (int size ) {
26+ if (size <= 0 ) {
27+ throw new IllegalArgumentException ("Buffer size must be positive" );
28+ }
1229 // noinspection unchecked
1330 this .buffer = (Item []) new Object [size ];
1431 this .putPointer = new CircularPointer (0 , size );
1532 this .getPointer = new CircularPointer (0 , size );
1633 }
1734
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+ */
1841 public boolean isEmpty () {
1942 return size .get () == 0 ;
2043 }
2144
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+ */
2251 public boolean isFull () {
2352 return size .get () == buffer .length ;
2453 }
2554
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+ */
2661 public Item get () {
2762 if (isEmpty ()) {
2863 return null ;
@@ -33,31 +68,64 @@ public Item get() {
3368 return item ;
3469 }
3570
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+ */
3679 public boolean put (Item item ) {
80+ if (item == null ) {
81+ throw new IllegalArgumentException ("Null items are not allowed" );
82+ }
83+
84+ boolean wasEmpty = isEmpty ();
3785 if (isFull ()) {
38- return false ;
86+ getPointer .getAndIncrement (); // Move get pointer to discard oldest item
87+ } else {
88+ size .incrementAndGet ();
3989 }
4090
4191 buffer [putPointer .getAndIncrement ()] = item ;
42- size .incrementAndGet ();
43- return true ;
92+ return wasEmpty ;
4493 }
4594
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+ */
46105 private static class CircularPointer {
47106 private int pointer ;
48107 private final int max ;
49108
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+ */
50115 CircularPointer (int pointer , int max ) {
51116 this .pointer = pointer ;
52117 this .max = max ;
53118 }
54119
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+ */
55126 public int getAndIncrement () {
56- if (pointer == max ) {
57- pointer = 0 ;
58- }
59127 int tmp = pointer ;
60- pointer ++ ;
128+ pointer = ( pointer + 1 ) % max ;
61129 return tmp ;
62130 }
63131 }
0 commit comments