ByteArrayByteBuffer.java
/*
* Copyright 2017-2023 original authors
*
* 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
*
* https://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 io.micronaut.core.io.buffer;
import io.micronaut.core.annotation.Experimental;
import io.micronaut.core.annotation.Internal;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Arrays;
/**
* A {@link ByteBuffer} implementation that is backed by a byte array.
*
* @since 4.7
*/
@Internal
@Experimental
public final class ByteArrayByteBuffer implements ByteBuffer<byte[]> {
private final byte[] underlyingBytes;
private int readerIndex;
private int writerIndex;
/**
* Construct a new {@link ByteArrayByteBuffer} for the given bytes.
*
* @param underlyingBytes the bytes to wrap
*/
ByteArrayByteBuffer(byte[] underlyingBytes) {
this(underlyingBytes, underlyingBytes.length);
}
/**
* Construct a new {@link ByteArrayByteBuffer} for the given bytes and capacity.
* If capacity is greater than the length of the underlyingBytes, extra bytes will be zeroed out.
* If capacity is less than the length of the underlyingBytes, the underlyingBytes will be truncated.
*
* @param underlyingBytes the bytes to wrap
* @param capacity the capacity of the buffer
*/
ByteArrayByteBuffer(byte[] underlyingBytes, int capacity) {
if (capacity < underlyingBytes.length) {
this.underlyingBytes = Arrays.copyOf(underlyingBytes, capacity);
} else if (capacity > underlyingBytes.length) {
this.underlyingBytes = new byte[capacity];
System.arraycopy(underlyingBytes, 0, this.underlyingBytes, 0, underlyingBytes.length);
} else {
this.underlyingBytes = underlyingBytes;
}
}
@Override
public byte[] asNativeBuffer() {
return underlyingBytes;
}
@Override
public int readableBytes() {
return underlyingBytes.length - readerIndex;
}
@Override
public int writableBytes() {
return underlyingBytes.length - writerIndex;
}
@Override
public int maxCapacity() {
return underlyingBytes.length;
}
@Override
public ByteArrayByteBuffer capacity(int capacity) {
return new ByteArrayByteBuffer(underlyingBytes, capacity);
}
@Override
public int readerIndex() {
return readerIndex;
}
@Override
public ByteArrayByteBuffer readerIndex(int readPosition) {
this.readerIndex = Math.min(readPosition, underlyingBytes.length);
return this;
}
@Override
public int writerIndex() {
return writerIndex;
}
@Override
public ByteArrayByteBuffer writerIndex(int position) {
this.writerIndex = Math.min(position, underlyingBytes.length);
return this;
}
@Override
public byte read() {
return underlyingBytes[readerIndex++];
}
@Override
public CharSequence readCharSequence(int length, Charset charset) {
String s = new String(underlyingBytes, readerIndex, length, charset);
readerIndex += length;
return s;
}
@Override
public ByteArrayByteBuffer read(byte[] destination) {
int count = Math.min(readableBytes(), destination.length);
System.arraycopy(underlyingBytes, readerIndex, destination, 0, count);
readerIndex += count;
return this;
}
@Override
public ByteArrayByteBuffer read(byte[] destination, int offset, int length) {
int count = Math.min(readableBytes(), Math.min(destination.length - offset, length));
System.arraycopy(underlyingBytes, readerIndex, destination, offset, count);
readerIndex += count;
return this;
}
@Override
public ByteArrayByteBuffer write(byte b) {
underlyingBytes[writerIndex++] = b;
return this;
}
@Override
public ByteArrayByteBuffer write(byte[] source) {
int count = Math.min(writableBytes(), source.length);
System.arraycopy(source, 0, underlyingBytes, writerIndex, count);
writerIndex += count;
return this;
}
@Override
public ByteArrayByteBuffer write(CharSequence source, Charset charset) {
write(source.toString().getBytes(charset));
return this;
}
@Override
public ByteArrayByteBuffer write(byte[] source, int offset, int length) {
int count = Math.min(writableBytes(), length);
System.arraycopy(source, offset, underlyingBytes, writerIndex, count);
writerIndex += count;
return this;
}
@Override
public ByteArrayByteBuffer write(ByteBuffer... buffers) {
for (ByteBuffer<?> buffer : buffers) {
write(buffer.toByteArray());
}
return this;
}
@Override
public ByteArrayByteBuffer write(java.nio.ByteBuffer... buffers) {
for (java.nio.ByteBuffer buffer : buffers) {
write(buffer.array());
}
return this;
}
@Override
public ByteArrayByteBuffer slice(int index, int length) {
return new ByteArrayByteBuffer(Arrays.copyOfRange(underlyingBytes, index, index + length), length);
}
@Override
public java.nio.ByteBuffer asNioBuffer() {
return java.nio.ByteBuffer.wrap(underlyingBytes, readerIndex, readableBytes());
}
@Override
public java.nio.ByteBuffer asNioBuffer(int index, int length) {
return java.nio.ByteBuffer.wrap(underlyingBytes, index, length);
}
@Override
public InputStream toInputStream() {
return new ByteArrayInputStream(underlyingBytes, readerIndex, readableBytes());
}
@Override
public OutputStream toOutputStream() {
throw new IllegalStateException("Not implemented");
}
@Override
public byte[] toByteArray() {
return Arrays.copyOfRange(underlyingBytes, readerIndex, readableBytes());
}
@Override
public String toString(Charset charset) {
return new String(underlyingBytes, readerIndex, readableBytes(), charset);
}
@Override
public int indexOf(byte b) {
for (int i = readerIndex; i < underlyingBytes.length; i++) {
if (underlyingBytes[i] == b) {
return i;
}
}
return -1;
}
@Override
public byte getByte(int index) {
return underlyingBytes[index];
}
}