Skip to content

Commit

Permalink
Updated FastBuffers to be really faster.
Browse files Browse the repository at this point in the history
  • Loading branch information
igr committed Jun 14, 2018
1 parent 002fc74 commit 1842ccb
Show file tree
Hide file tree
Showing 24 changed files with 572 additions and 2,400 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,7 @@ public void reset() {
* @see ByteArrayOutputStream#writeTo(OutputStream)
*/
public void writeTo(final OutputStream out) throws IOException {
int index = buffer.index();
for (int i = 0; i < index; i++) {
byte[] buf = buffer.array(i);
out.write(buf);
}
out.write(buffer.array(index), 0, buffer.offset());
out.write(buffer.toArray());
}

/**
Expand Down
7 changes: 1 addition & 6 deletions jodd-core/src/main/java/jodd/io/FastCharArrayWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,7 @@ public void reset() {
* @see CharArrayWriter#writeTo(Writer)
*/
public void writeTo(final Writer out) throws IOException {
int index = buffer.index();
for (int i = 0; i < index; i++) {
char[] buf = buffer.array(i);
out.write(buf);
}
out.write(buffer.array(index), 0, buffer.offset());
out.write(buffer.toArray());
}

/**
Expand Down
221 changes: 51 additions & 170 deletions jodd-core/src/main/java/jodd/util/buffer/FastBooleanBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,262 +25,143 @@

package jodd.util.buffer;

import java.util.Arrays;

/**
* Fast, fast <code>boolean</code> buffer.
* This buffer implementation does not store all data
* in single array, but in array of chunks.
* Faster {@code boolean} buffer. Works faster for smaller buffer sizes.
* After eg. length of 2048 the performances are practically the same.
*/
public class FastBooleanBuffer {

private boolean[][] buffers = new boolean[16][];
private int buffersCount;
private int currentBufferIndex = -1;
private boolean[] currentBuffer;
private boolean[] buffer;
private int offset;
private int size;
private final int minChunkLen;

/**
* Creates a new <code>boolean</code> buffer. The buffer capacity is
* initially 1024 bytes, though its size increases if necessary.
* Creates a new {@code boolean} buffer. The buffer capacity is
* initially 64 booleans, though its size increases if necessary.
*/
public FastBooleanBuffer() {
this.minChunkLen = 1024;
this.buffer = new boolean[64];
}

/**
* Creates a new <code>boolean</code> buffer, with a buffer capacity of
* the specified size, in bytes.
* Creates a new {@code boolean} buffer, with a buffer capacity of
* the specified size.
*
* @param size the initial size.
* @throws IllegalArgumentException if size is negative.
*/
public FastBooleanBuffer(final int size) {
if (size < 0) {
throw new IllegalArgumentException("Invalid size: " + size);
}
this.minChunkLen = size;
this.buffer = new boolean[size];
}

/**
* Prepares next chunk to match new size.
* The minimal length of new chunk is <code>minChunkLen</code>.
* Grows the buffer.
*/
private void needNewBuffer(final int newSize) {
int delta = newSize - size;
int newBufferSize = Math.max(minChunkLen, delta);

currentBufferIndex++;
currentBuffer = new boolean[newBufferSize];
offset = 0;

// add buffer
if (currentBufferIndex >= buffers.length) {
int newLen = buffers.length << 1;
boolean[][] newBuffers = new boolean[newLen][];
System.arraycopy(buffers, 0, newBuffers, 0, buffers.length);
buffers = newBuffers;
private void grow(final int minCapacity) {
final int oldCapacity = buffer.length;
int newCapacity = oldCapacity << 1;
if (newCapacity - minCapacity < 0) {
// special case, min capacity is larger then a grow
newCapacity = minCapacity + 512;
}
buffers[currentBufferIndex] = currentBuffer;
buffersCount++;
buffer = Arrays.copyOf(buffer, newCapacity);
}

/**
* Appends <code>boolean</code> array to buffer.
* Appends single {@code boolean} to buffer.
*/
public FastBooleanBuffer append(final boolean[] array, final int off, final int len) {
int end = off + len;
if ((off < 0)
|| (len < 0)
|| (end > array.length)) {
throw new IndexOutOfBoundsException();
public void append(final boolean element) {
if (offset - buffer.length >= 0) {
grow(offset);
}
if (len == 0) {
return this;
}
int newSize = size + len;
int remaining = len;

if (currentBuffer != null) {
// first try to fill current buffer
int part = Math.min(remaining, currentBuffer.length - offset);
System.arraycopy(array, end - remaining, currentBuffer, offset, part);
remaining -= part;
offset += part;
size += part;
}

if (remaining > 0) {
// still some data left
// ask for new buffer
needNewBuffer(newSize);
buffer[offset++] = element;
}

// then copy remaining
// but this time we are sure that it will fit
int part = Math.min(remaining, currentBuffer.length - offset);
System.arraycopy(array, end - remaining, currentBuffer, offset, part);
offset += part;
size += part;
/**
* Appends {@code boolean} array to buffer.
*/
public FastBooleanBuffer append(final boolean[] array, final int off, final int len) {
if (offset + len - buffer.length > 0) {
grow(offset + len);
}

System.arraycopy(array, off, buffer, offset, len);
offset += len;
return this;
}

/**
* Appends <code>boolean</code> array to buffer.
* Appends {@code boolean} array to buffer.
*/
public FastBooleanBuffer append(final boolean[] array) {
return append(array, 0, array.length);
}

/**
* Appends single <code>boolean</code> to buffer.
*/
public FastBooleanBuffer append(final boolean element) {
if ((currentBuffer == null) || (offset == currentBuffer.length)) {
needNewBuffer(size + 1);
}

currentBuffer[offset] = element;
offset++;
size++;

return this;
}

/**
* Appends another fast buffer to this one.
*/
public FastBooleanBuffer append(final FastBooleanBuffer buff) {
if (buff.size == 0) {
if (buff.offset == 0) {
return this;
}
for (int i = 0; i < buff.currentBufferIndex; i++) {
append(buff.buffers[i]);
}
append(buff.currentBuffer, 0, buff.offset);
append(buff.buffer, 0, buff.offset);
return this;
}

/**
* Returns buffer size.
*/
public int size() {
return size;
return offset;
}

/**
* Tests if this buffer has no elements.
*/
public boolean isEmpty() {
return size == 0;
}

/**
* Returns current index of inner <code>boolean</code> array chunk.
* Represents the index of last used inner array chunk.
*/
public int index() {
return currentBufferIndex;
}

/**
* Returns the offset of last used element in current inner array chunk.
*/
public int offset() {
return offset;
}

/**
* Returns <code>boolean</code> inner array chunk at given index.
* May be used for iterating inner chunks in fast manner.
*/
public boolean[] array(final int index) {
return buffers[index];
return offset == 0;
}

/**
* Resets the buffer content.
*/
public void clear() {
size = 0;
offset = 0;
currentBufferIndex = -1;
currentBuffer = null;
buffersCount = 0;
}

/**
* Creates <code>boolean</code> array from buffered content.
* Creates {@code boolean} array from buffered content.
*/
public boolean[] toArray() {
int pos = 0;
boolean[] array = new boolean[size];

if (currentBufferIndex == -1) {
return array;
}

for (int i = 0; i < currentBufferIndex; i++) {
int len = buffers[i].length;
System.arraycopy(buffers[i], 0, array, pos, len);
pos += len;
}

System.arraycopy(buffers[currentBufferIndex], 0, array, pos, offset);

return array;
return Arrays.copyOf(buffer, offset);
}

/**
* Creates <code>boolean</code> subarray from buffered content.
*/
public boolean[] toArray(int start, final int len) {
int remaining = len;
int pos = 0;
boolean[] array = new boolean[len];
/**
* Creates {@code boolean} subarray from buffered content.
*/
public boolean[] toArray(final int start, final int len) {
final boolean[] array = new boolean[len];

if (len == 0) {
return array;
}

int i = 0;
while (start >= buffers[i].length) {
start -= buffers[i].length;
i++;
}
System.arraycopy(buffer, start, array, 0, len);

while (i < buffersCount) {
boolean[] buf = buffers[i];
int c = Math.min(buf.length - start, remaining);
System.arraycopy(buf, start, array, pos, c);
pos += c;
remaining -= c;
if (remaining == 0) {
break;
}
start = 0;
i++;
}
return array;
}

/**
* Returns <code>boolean</code> element at given index.
* Returns {@code boolean} element at given index.
*/
public boolean get(int index) {
if ((index >= size) || (index < 0)) {
public boolean get(final int index) {
if (index >= offset) {
throw new IndexOutOfBoundsException();
}
int ndx = 0;
while (true) {
boolean[] b = buffers[ndx];
if (index < b.length) {
return b[index];
}
ndx++;
index -= b.length;
}
return buffer[index];
}


}
Loading

0 comments on commit 1842ccb

Please sign in to comment.