/*
* Copyright 2013 eXo Platform SAS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package juzu.impl.common;
import java.io.IOException;
/**
* A growing char buffer that can be read and written.
*
* @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
*/
public class CharBuffer implements Appendable {
/** The initial size. */
private static final int INITIAL_SIZE = 16;
/** . */
private char[] chars;
/** . */
private int from;
/** . */
private int to;
public CharBuffer() {
this(INITIAL_SIZE);
}
public CharBuffer(int length) {
if (length < 1) {
throw new IllegalArgumentException();
}
this.chars = new char[length];
this.from = 0;
this.to = 0;
}
public int getLength() {
return to - from;
}
public int getSize() {
return chars.length;
}
/**
* Read from a char array.
*
* @param src the char array source
* @param at the first index of the chars to read
* @param len the amount of chars to read
* @throws NullPointerException if the source is null
* @throws IllegalArgumentException if the len argument is negative
* @throws IndexOutOfBoundsException if the source is adressed out of its bounds
*/
public void readFrom(char[] src, int at, int len) throws NullPointerException, IllegalArgumentException, IndexOutOfBoundsException {
if (src == null) {
throw new NullPointerException("Buffer cannot be null");
}
if (at < 0) {
throw new IndexOutOfBoundsException("Begin pointer cannot be negative: " + at);
}
if (len < 0) {
throw new IllegalArgumentException("Length cannot be negative: " + len);
}
if (at + len > src.length) {
throw new IndexOutOfBoundsException("End pointer cannot be greater than buffer: " + (at + len));
}
// Check if we have enough remaining space
ensure(len);
// Copy data
System.arraycopy(src, at, this.chars, to, len);
to += len;
}
/**
* Write to a char array.
*
* @param dst the char array destination
* @param at the first index of the chars to write
* @param len the amount of chars to write
* @return the amount of chars written
* @throws NullPointerException if the destintation is null
* @throws IllegalArgumentException if the len argument is null
* @throws IndexOutOfBoundsException if the destination is addressed out of its bounds
*/
public int writeTo(char[] dst, int at, int len) throws NullPointerException, IllegalArgumentException, IndexOutOfBoundsException {
if (dst == null) {
throw new NullPointerException("Destination cannot be null");
}
if (at < 0) {
throw new IndexOutOfBoundsException("Begin pointer cannot be negative: " + at);
}
if (len < 0) {
throw new IllegalArgumentException("Length cannot be negative: " + len);
}
if (at + len > dst.length) {
throw new IndexOutOfBoundsException("End pointer cannot be greater than buffer: " + (at + len));
}
// Determine how much we copy
int l = Math.min(to - from, len);
System.arraycopy(this.chars, from, dst, at, l);
from += l;
return l;
}
/**
* Write to an appendable.
*
* @param dst the appendable destination
* @return the amount of chars written
* @throws NullPointerException if the destination is null
* @throws IOException any IOException thrown by the <code>dst</code> argument
*/
public int writeTo(Appendable dst) throws NullPointerException, IOException {
if (dst == null) {
throw new NullPointerException("Destination cannot be null");
}
//
int from = this.from;
int to = this.to;
char[] chars = this.chars;
//
final int delta = to - from;
if (delta > 0) {
while (from < to) {
dst.append(chars[from++]);
}
this.from = from;
this.to = to;
this.chars = chars;
}
//
return delta;
}
private void ensure(int amount) {
int remaining = chars.length - to;
if (remaining < amount) {
char[] tmp = new char[chars.length * 2];
System.arraycopy(chars, from, tmp, from, to - from);
this.chars = tmp;
}
}
// Appendable implementation *****************************************************************************************
public Appendable append(CharSequence csq) throws IOException {
return append(csq, 0, csq.length());
}
public Appendable append(CharSequence csq, int start, int end) throws IOException {
if (start < 0) {
throw new IndexOutOfBoundsException("Start " + start + " cannot be negative");
}
if (start > end) {
throw new IndexOutOfBoundsException("Start " + start + " cannot be greater then end " + end);
}
if (end > csq.length()) {
throw new IndexOutOfBoundsException("End " + end + " cannot be greater then char sequence " + csq.length());
}
int len = end - start;
ensure(len);
while (start < end) {
chars[to++] = csq.charAt(start++);
}
return this;
}
public Appendable append(char c) throws IOException {
ensure(1);
chars[to++] = c;
return this;
}
}