2 * Copyright 2000-2015 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.util.containers;
18 import com.intellij.util.ArrayUtil;
19 import org.jetbrains.annotations.NotNull;
22 * A single threaded, resizable, circular char queue backed by an array.
24 public class CircularCharBuffer {
26 private char[] myArray;
27 private final int myMaxCapacity;
32 public CircularCharBuffer(int initialCapacity) {
33 this(initialCapacity, -1);
36 public CircularCharBuffer(int initialCapacity, int maxCapacity) {
37 assert maxCapacity < 0 || initialCapacity <= maxCapacity;
38 myArray = new char[initialCapacity];
39 myMaxCapacity = maxCapacity;
45 public void add(char c) {
46 resizeIfNeeded(mySize + 1);
50 public void add(char[] buffer) {
51 resizeIfNeeded(mySize + buffer.length);
52 for (char c : buffer) {
57 public void add(@NotNull String str) {
58 resizeIfNeeded(mySize + str.length());
59 for (int i = 0; i < str.length(); i++) {
64 private void doAdd(char c) {
67 int length = myArray.length;
68 if (myTail >= length) {
72 if (mySize > length) {
85 char res = myArray[myHead];
87 if (myHead >= myArray.length) {
95 public String getText() {
97 return new String(myArray, 0, mySize);
100 public boolean isEmpty() {
108 private boolean resizeIfNeeded(int newSize) {
109 int length = myArray.length;
110 if (newSize <= length) {
113 if (myMaxCapacity > -1 && length == myMaxCapacity) {
117 int newLength = Math.max(length << 1, newSize);
118 if (myMaxCapacity > -1) {
119 newLength = Math.min(myMaxCapacity, newLength);
121 char[] newArray = new char[newLength];
122 System.arraycopy(myArray, myHead, newArray, 0, mySize);
124 myTail = mySize % newArray.length;
129 * Updates internal data to make sure {@code myHead} points to zero index of {@code myArray}.
130 * As a result of this operation there will be no visible changes to clients.
132 private void normalize() {
136 int length = myArray.length;
137 if (myHead < myTail) {
138 moveSubArrayLeft(myArray, myHead, mySize, myHead);
141 int headSize = myTail;
142 int tailSize = length - myHead;
143 reverseSubArray(myArray, 0, headSize);
144 reverseSubArray(myArray, length - tailSize, tailSize);
145 reverseSubArray(myArray, 0, length);
146 moveSubArrayLeft(myArray, length - headSize, headSize, length - headSize - tailSize);
149 myTail = mySize % length;
152 private static void moveSubArrayLeft(char[] array, int startInd, int length, int moveLeftCount) {
153 //noinspection ManualArrayCopy
154 for (int i = startInd; i < startInd + length; i++) {
155 array[i - moveLeftCount] = array[i];
159 private static void reverseSubArray(char[] array, int startInd, int length) {
160 for (int i = 0; i < length / 2; i++) {
161 ArrayUtil.swap(array, startInd + i, startInd + length - 1 - i);