Java Ring Buffer

Ring Buffer 是一个固定容量大小的数组。维护两个下标,一个写入,一个读取。
类似一个环,怎么计算写入和读取的下标,有2种方式实现:
1.记录当前的已经写入的数量
2.记录一个反转标记

//记录写入数量,实现RingBuffer
public class RingBufferFillCount {

    public Object[] elements = null;
    private int capacity = 0;
    private int writePos = 0;
    private int available = 0;

    public RingBufferFillCount(int capacity) {
        this.capacity = capacity;
        this.elements = new Object[capacity];
    }

    public void reset() {
        this.writePos = 0;
        this.available = 0;
    }

    public int getCapacity() {
        return capacity;
    }

    public int getAvailable() {
        return available;
    }

    public int remainingCapacity() {
        return this.capacity - this.available;
    }

    public boolean put(Object element) {
        if (available < capacity) {
            if (writePos >= capacity) {
                writePos = 0;
            }
            elements[writePos] = element;
            writePos++;
            available++;
            return true;
        }
        return false;
    }

    public Object take() {
        if (available == 0) {
            return null;
        }
        int nextSlot = writePos - available;
        if (nextSlot < 0) {
            nextSlot += capacity;
        }
        Object nextObj = elements[nextSlot];
        available--;
        return nextObj;
    }

    public int put(Object[] newElements) {
        return put(newElements, newElements.length);
    }

    public int put(Object[] newElements, int length) {
        int readPos = 0;
        if (this.writePos > this.available) {
            //直接追加
            if (length <= this.capacity - this.writePos) {
                for (; readPos < length; readPos++) {
                    this.elements[this.writePos++] = newElements[readPos];
                }
                this.available += readPos;
                return length;
            } else {
                //需要在数组尾部和头部添加
                for (; this.writePos < this.capacity; this.writePos++) {
                    this.elements[this.writePos] = newElements[readPos++];
                }
                //重置写入下标
                this.writePos = 0;
                //计算还能写入多少
                int endPos = Math.min(length - readPos, capacity - available - readPos);
                for (; this.writePos < endPos; this.writePos++) {
                    this.elements[this.writePos] = newElements[readPos++];
                }
                this.available += readPos;
                return readPos;
            }
        } else {
            int endPos = this.capacity - this.available + this.writePos;
            for (; this.writePos < endPos; this.writePos++) {
                this.elements[this.writePos] = newElements[readPos++];
            }
            this.available += readPos;
            return readPos;
        }
    }

    public int take(Object[] into) {
        return take(into, into.length);
    }


    public int take(Object[] into, int length) {
        int intoPos = 0;

        if (available <= writePos) {
            int nextPos = writePos - available;
            int endPos = nextPos + Math.min(available, length);
            for (; nextPos < endPos; nextPos++) {
                into[intoPos++] = this.elements[nextPos];
            }
            this.available -= intoPos;
            return intoPos;
        } else {
            int nextPos = writePos - available + capacity;
            int leftInTop = capacity - nextPos;
            if (length <= leftInTop) {
                //copy directly
                for (; intoPos < length; intoPos++) {
                    into[intoPos] = this.elements[nextPos++];
                }
                this.available -= length;
                return length;
            } else {
                //copy top
                for (; nextPos < capacity; nextPos++) {
                    into[intoPos++] = this.elements[nextPos];
                }
                //copy bottom - from 0 to writePos
                nextPos = 0;
                int leftToCopy = length - intoPos;
                int endPos = Math.min(writePos, leftToCopy);
                for (; nextPos < endPos; nextPos++) {
                    into[intoPos++] = this.elements[nextPos];
                }
                this.available -= intoPos;
                return intoPos;
            }
        }
    }
}
//使用反转标记,实现RingBuffer
public class RingBufferFlipMarker {

    public Object[] elements = null;

    public int capacity = 0;
    public int writePos = 0;
    public int readPos = 0;
    public boolean flipped = false;

    public RingBufferFlipMarker(int capacity) {
        this.capacity = capacity;
        this.elements = new Object[capacity];
    }

    public void reset() {
        this.writePos = 0;
        this.readPos = 0;
        this.flipped = false;
    }

    public int remainingCapacity() {
        if (!flipped) {
            return capacity - writePos;
        }
        return readPos - writePos;
    }

    public int available() {
        if (!flipped) {
            return writePos - readPos;
        }
        return capacity - (writePos - readPos);
    }

    public boolean put(Object element) {
        if (!flipped) {
            if (writePos == capacity) {
                writePos = 0;
                flipped = true;
                if (writePos < readPos) {
                    elements[writePos++] = element;
                    return true;
                } else {
                    return false;
                }
            } else {
                elements[writePos++] = element;
                return true;
            }
        } else {
            if (writePos < readPos) {
                elements[writePos++] = element;
                return true;
            } else {
                return false;
            }
        }
    }

    public Object take() {
        if (!flipped) {
            if (readPos < writePos) {
                return elements[readPos++];
            } else {
                return null;
            }
        } else {
            if (readPos == capacity) {
                readPos = 0;
                flipped = false;
                if (readPos < writePos) {
                    return elements[readPos++];
                } else {
                    return null;
                }
            } else {
                return elements[readPos++];
            }
        }
    }

    public int put(Object[] newElements, int length) {
        int newElementsReadPos = 0;
        if (!flipped) {
            //readPos lower than writePos - free sections are:
            //1) from writePos to capacity
            //2) from 0 to readPos
            if (length <= capacity - writePos) {
                //new elements fit into top of elements array - copy directly
                for (; newElementsReadPos < length; newElementsReadPos++) {
                    this.elements[this.writePos++] = newElements[newElementsReadPos];
                }
                return newElementsReadPos;
            } else {
                //new elements must be divided between top and bottom of elements array
                //writing to top
                for (; this.writePos < capacity; this.writePos++) {
                    this.elements[this.writePos] = newElements[newElementsReadPos++];
                }
                //writing to bottom
                this.writePos = 0;
                this.flipped = true;
                int endPos = Math.min(this.readPos, length - newElementsReadPos);
                for (; this.writePos < endPos; this.writePos++) {
                    this.elements[writePos] = newElements[newElementsReadPos++];
                }
                return newElementsReadPos;
            }
        } else {
            //readPos higher than writePos - free sections are:
            //1) from writePos to readPos
            int endPos = Math.min(this.readPos, this.writePos + length);
            for (; this.writePos < endPos; this.writePos++) {
                this.elements[this.writePos] = newElements[newElementsReadPos++];
            }
            return newElementsReadPos;
        }
    }

    public int take(Object[] into, int length) {
        int intoWritePos = 0;
        if (!flipped) {
            //writePos higher than readPos - available section is writePos - readPos
            int endPos = Math.min(this.writePos, this.readPos + length);
            for (; this.readPos < endPos; this.readPos++) {
                into[intoWritePos++] = this.elements[this.readPos];
            }
            return intoWritePos;
        } else {
            //readPos higher than writePos - available sections are
            //top + bottom of elements array
            if (length <= capacity - readPos) {
                //length is lower than the elements available at the top
                //of the elements array - copy directly
                for (; intoWritePos < length; intoWritePos++) {
                    into[intoWritePos] = this.elements[this.readPos++];
                }
                return intoWritePos;
            } else {
                //length is higher than elements available at the top of the elements array
                //split copy into a copy from both top and bottom of elements array.
                //copy from top
                for (; this.readPos < capacity; this.readPos++) {
                    into[intoWritePos++] = this.elements[this.readPos];
                }
                //copy from bottom
                this.readPos = 0;
                this.flipped = false;
                int endPos = Math.min(this.writePos, length - intoWritePos);
                for (; this.readPos < endPos; this.readPos++) {
                    into[intoWritePos++] = this.elements[this.readPos];
                }
                return intoWritePos;
            }
        }
    }
}