Unbounded FIFO Buffer

0

Add

Create a buffer of 3 elements.

UnboundedFifoBuffer buf = new UnboundedFifoBuffer(3);

Internally the implementation creates an extra element. Head and tail indices are equal to 0 as we have not added or removed any elements. As we add elements, tail index increases. When size of buffer equals the allocated buffer length, array is expanded so that size=size*2+1.

 

Unbounded FIFO Buffer

 

 

Remove

When we remove element, we get an extra vacant element. The head index points to 1. As we remove more elements, the head index increases further. When we add new elements, it will re-use the vacant elements.
Unbounded FIFO Buffer

Add again

In the above example, the tail index is pointing to the last element of the array. Since we have vacant elements due to the remove operation, instead of resizing the array, it will re-use the vacant elements. The tail index will point to 0 so that the next add will fill the 0 index element. As we add new elements, the tail index will increase. Since tail index is < head index, the size would be buffer length – head + tail.
Unbounded FIFO Buffer

Iterator

Iterator returns elements in the incremental order starting from head, till it reaches tail. If tail < head, element order will be from head to array’s last element and then 0 to tail index. In the example, iterator will return 5, 6, 7 (last element of array), 8 (index=0), 9, 10(index=tail)
Unbounded FIFO Buffer

Remove during iteration

If it is the first element, it can be removed quickly else we will have to left shift elements. In the below example, iterator returns first element 5. We do next() to get 6, and then call remove.

 

Unbounded FIFO Buffer

Re-sizing

Since size equals buffer length, adding a new element will expand the array. The elements will be re-positioned in the new array in the order from head->tail.
Unbounded FIFO Buffer

Unit test

    
    public void testBuffLen() {
        //Create a buffer of 3 elements
        UnboundedFifoBuffer buf = new UnboundedFifoBuffer(3);
        //Internally the implementation creates an extra element, not sure why?
        assertEquals(4, buf.buffer.length);
        //Head and tail indexes are equal to 0 as we have not added or removed any elements
        assertEquals(0, buf.head);
        assertEquals(0, buf.tail);

        //As we add elements, tail index is incremented
        buf.add(1);

        assertEquals(0, buf.head);
        assertEquals(1, buf.tail);
        assertEquals(1, buf.size());

        buf.add(2);

        assertEquals(2, buf.size());

        buf.add(3);

        assertEquals(3, buf.size());
        assertEquals(4, buf.buffer.length);

        //When size of buffer equals the allocated buffer length, array is expanded so that size=size*2+1
        buf.add(4);
        assertEquals(4, buf.size());
        assertEquals(7, buf.buffer.length);

        buf.add(5);
        buf.add(6);

        assertEquals(6, buf.size());
        assertEquals(7, buf.buffer.length);

        //When we remove element, we get an extra vacant element.
        buf.remove();

        //Since the first element is removed, head index is incremented to 1
        //When we add new elements, instead of re-sizing, it will re-use the vacant elements
        assertEquals(5, buf.size());
        assertEquals(1, buf.head);
        assertEquals(6, buf.tail);

        //As we remove more elements, the head index is incremented further
        buf.remove();
        buf.remove();
        buf.remove();

        assertEquals(2, buf.size());
        assertEquals(4, buf.head);
        assertEquals(6, buf.tail);

        //Tail index is pointing to the end element in buffer. Since we have vacant elements due to the remove operation,
        //instead of resizing the array, it will re-use the vacant elements.
        buf.add(7);

        //Tail index now points to 0 to reuse the vacant elements
        assertEquals(3, buf.size());
        assertEquals(4, buf.head);
        assertEquals(0, buf.tail);
        assertEquals(7, buf.buffer.length);

        //Get method returns element pointing by the head index
        assertEquals(5, buf.get());
        assertEquals(5, buf.get());

        //Add new elements, tail index is incremented
        buf.add(8);
        buf.add(9);

        //Tail index is < head index so size = buffer length - head + tail
        assertEquals(4, buf.head);
        assertEquals(2, buf.tail);
        assertEquals(5, buf.size());
        assertEquals(7, buf.buffer.length);

        buf.add(10);
        assertEquals(4, buf.head);
        assertEquals(3, buf.tail);
        assertEquals(6, buf.size());

        //Size equals buffer length so adding new element will expand the array
        buf.add(11);
        assertEquals(0, buf.head);
        assertEquals(7, buf.tail);
        assertEquals(13, buf.buffer.length);
    }
Share.

Leave A Reply