mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
add FastCharBuffer
This commit is contained in:
parent
9dfcac028e
commit
5f45b2275e
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Hutool Team and hutool.cn
|
||||||
|
*
|
||||||
|
* 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 org.dromara.hutool.core.io.buffer;
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.io.IoUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 快速缓冲抽象类,用于快速读取、写入数据到缓冲区,减少内存复制<br>
|
||||||
|
* 相对于普通Buffer,使用二维数组扩展长度,减少内存复制,提升性能
|
||||||
|
*
|
||||||
|
* @author Looly
|
||||||
|
*/
|
||||||
|
public abstract class FastBuffer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一个缓冲区的最小字节数
|
||||||
|
*/
|
||||||
|
protected final int minChunkLen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓冲数
|
||||||
|
*/
|
||||||
|
protected int buffersCount;
|
||||||
|
/**
|
||||||
|
* 当前缓冲索引
|
||||||
|
*/
|
||||||
|
protected int currentBufferIndex = -1;
|
||||||
|
/**
|
||||||
|
* 当前缓冲偏移量
|
||||||
|
*/
|
||||||
|
protected int offset;
|
||||||
|
/**
|
||||||
|
* 缓冲字节数
|
||||||
|
*/
|
||||||
|
protected int size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param size 一个缓冲区的最小字节数
|
||||||
|
*/
|
||||||
|
public FastBuffer(int size) {
|
||||||
|
if (size <= 0) {
|
||||||
|
size = IoUtil.DEFAULT_BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
this.minChunkLen = Math.abs(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前缓冲位于缓冲区的索引位
|
||||||
|
*
|
||||||
|
* @return {@link #currentBufferIndex}
|
||||||
|
*/
|
||||||
|
public int index() {
|
||||||
|
return currentBufferIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前缓冲偏移量
|
||||||
|
*
|
||||||
|
* @return 当前缓冲偏移量
|
||||||
|
*/
|
||||||
|
public int offset() {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复位缓冲
|
||||||
|
*/
|
||||||
|
public void reset() {
|
||||||
|
size = 0;
|
||||||
|
offset = 0;
|
||||||
|
currentBufferIndex = -1;
|
||||||
|
buffersCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓冲总长度
|
||||||
|
*
|
||||||
|
* @return 缓冲总长度
|
||||||
|
*/
|
||||||
|
public int length() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为空
|
||||||
|
*
|
||||||
|
* @return 是否为空
|
||||||
|
*/
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分配下一个缓冲区,不会小于1024
|
||||||
|
*
|
||||||
|
* @param newSize 理想缓冲区字节数
|
||||||
|
*/
|
||||||
|
abstract protected void needNewBuffer(final int newSize);
|
||||||
|
}
|
@ -26,37 +26,16 @@ import org.dromara.hutool.core.lang.Assert;
|
|||||||
* @author biezhi, looly
|
* @author biezhi, looly
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
public class FastByteBuffer {
|
public class FastByteBuffer extends FastBuffer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 缓冲集
|
* 缓冲集
|
||||||
*/
|
*/
|
||||||
private byte[][] buffers = new byte[16][];
|
private byte[][] buffers = new byte[16][];
|
||||||
/**
|
|
||||||
* 缓冲数
|
|
||||||
*/
|
|
||||||
private int buffersCount;
|
|
||||||
/**
|
|
||||||
* 当前缓冲索引
|
|
||||||
*/
|
|
||||||
private int currentBufferIndex = -1;
|
|
||||||
/**
|
/**
|
||||||
* 当前缓冲
|
* 当前缓冲
|
||||||
*/
|
*/
|
||||||
private byte[] currentBuffer;
|
private byte[] currentBuffer;
|
||||||
/**
|
|
||||||
* 当前缓冲偏移量
|
|
||||||
*/
|
|
||||||
private int offset;
|
|
||||||
/**
|
|
||||||
* 缓冲字节数
|
|
||||||
*/
|
|
||||||
private int size;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 一个缓冲区的最小字节数
|
|
||||||
*/
|
|
||||||
private final int minChunkLen;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造
|
* 构造
|
||||||
@ -70,35 +49,8 @@ public class FastByteBuffer {
|
|||||||
*
|
*
|
||||||
* @param size 一个缓冲区的最小字节数
|
* @param size 一个缓冲区的最小字节数
|
||||||
*/
|
*/
|
||||||
public FastByteBuffer(int size) {
|
public FastByteBuffer(final int size) {
|
||||||
if (size <= 0) {
|
super(size);
|
||||||
size = IoUtil.DEFAULT_BUFFER_SIZE;
|
|
||||||
}
|
|
||||||
this.minChunkLen = Math.abs(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分配下一个缓冲区,不会小于1024
|
|
||||||
*
|
|
||||||
* @param newSize 理想缓冲区字节数
|
|
||||||
*/
|
|
||||||
private void needNewBuffer(final int newSize) {
|
|
||||||
final int delta = newSize - size;
|
|
||||||
final int newBufferSize = Math.max(minChunkLen, delta);
|
|
||||||
|
|
||||||
currentBufferIndex++;
|
|
||||||
currentBuffer = new byte[newBufferSize];
|
|
||||||
offset = 0;
|
|
||||||
|
|
||||||
// add buffer
|
|
||||||
if (currentBufferIndex >= buffers.length) {
|
|
||||||
final int newLen = buffers.length << 1;
|
|
||||||
final byte[][] newBuffers = new byte[newLen][];
|
|
||||||
System.arraycopy(buffers, 0, newBuffers, 0, buffers.length);
|
|
||||||
buffers = newBuffers;
|
|
||||||
}
|
|
||||||
buffers[currentBufferIndex] = currentBuffer;
|
|
||||||
buffersCount++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -190,42 +142,6 @@ public class FastByteBuffer {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 长度
|
|
||||||
*
|
|
||||||
* @return 长度
|
|
||||||
*/
|
|
||||||
public int size() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否为空
|
|
||||||
*
|
|
||||||
* @return 是否为空
|
|
||||||
*/
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return size == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前缓冲位于缓冲区的索引位
|
|
||||||
*
|
|
||||||
* @return {@link #currentBufferIndex}
|
|
||||||
*/
|
|
||||||
public int index() {
|
|
||||||
return currentBufferIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前缓冲偏移量
|
|
||||||
*
|
|
||||||
* @return 当前缓冲偏移量
|
|
||||||
*/
|
|
||||||
public int offset() {
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据索引位返回缓冲集中的缓冲
|
* 根据索引位返回缓冲集中的缓冲
|
||||||
*
|
*
|
||||||
@ -236,15 +152,10 @@ public class FastByteBuffer {
|
|||||||
return buffers[index];
|
return buffers[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* 复位缓冲
|
|
||||||
*/
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
size = 0;
|
super.reset();
|
||||||
offset = 0;
|
|
||||||
currentBufferIndex = -1;
|
|
||||||
currentBuffer = null;
|
currentBuffer = null;
|
||||||
buffersCount = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -254,9 +165,9 @@ public class FastByteBuffer {
|
|||||||
* @return 快速缓冲中的数据
|
* @return 快速缓冲中的数据
|
||||||
*/
|
*/
|
||||||
public byte[] toArrayZeroCopyIfPossible() {
|
public byte[] toArrayZeroCopyIfPossible() {
|
||||||
if(1 == currentBufferIndex){
|
if (1 == currentBufferIndex) {
|
||||||
final int len = buffers[0].length;
|
final int len = buffers[0].length;
|
||||||
if(len == size){
|
if (len == size) {
|
||||||
return buffers[0];
|
return buffers[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -284,10 +195,10 @@ public class FastByteBuffer {
|
|||||||
Assert.isTrue(start >= 0, "Start must be greater than zero!");
|
Assert.isTrue(start >= 0, "Start must be greater than zero!");
|
||||||
Assert.isTrue(len >= 0, "Length must be greater than zero!");
|
Assert.isTrue(len >= 0, "Length must be greater than zero!");
|
||||||
|
|
||||||
if(start >= this.size || len == 0){
|
if (start >= this.size || len == 0) {
|
||||||
return new byte[0];
|
return new byte[0];
|
||||||
}
|
}
|
||||||
if(len > (this.size - start)){
|
if (len > (this.size - start)) {
|
||||||
len = this.size - start;
|
len = this.size - start;
|
||||||
}
|
}
|
||||||
int remaining = len;
|
int remaining = len;
|
||||||
@ -301,8 +212,9 @@ public class FastByteBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (i < buffersCount) {
|
while (i < buffersCount) {
|
||||||
final int bufLen = Math.min(buffers[i].length - start, remaining);
|
final byte[] buf = buffers[i];
|
||||||
System.arraycopy(buffers[i], start, result, pos, bufLen);
|
final int bufLen = Math.min(buf.length - start, remaining);
|
||||||
|
System.arraycopy(buf, start, result, pos, bufLen);
|
||||||
pos += bufLen;
|
pos += bufLen;
|
||||||
remaining -= bufLen;
|
remaining -= bufLen;
|
||||||
if (remaining == 0) {
|
if (remaining == 0) {
|
||||||
@ -335,4 +247,23 @@ public class FastByteBuffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void needNewBuffer(final int newSize) {
|
||||||
|
final int delta = newSize - size;
|
||||||
|
final int newBufferSize = Math.max(minChunkLen, delta);
|
||||||
|
|
||||||
|
currentBufferIndex++;
|
||||||
|
currentBuffer = new byte[newBufferSize];
|
||||||
|
offset = 0;
|
||||||
|
|
||||||
|
// add buffer
|
||||||
|
if (currentBufferIndex >= buffers.length) {
|
||||||
|
final int newLen = buffers.length << 1;
|
||||||
|
final byte[][] newBuffers = new byte[newLen][];
|
||||||
|
System.arraycopy(buffers, 0, newBuffers, 0, buffers.length);
|
||||||
|
buffers = newBuffers;
|
||||||
|
}
|
||||||
|
buffers[currentBufferIndex] = currentBuffer;
|
||||||
|
buffersCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,346 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
|
||||||
|
*
|
||||||
|
* 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 org.dromara.hutool.core.io.buffer;
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.io.IoUtil;
|
||||||
|
import org.dromara.hutool.core.lang.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代码移植自jetbrick<br>
|
||||||
|
* 快速字符缓冲,将数据存放在缓冲集中,取代以往的单一数组
|
||||||
|
*
|
||||||
|
* @author jetbrick, looly
|
||||||
|
*/
|
||||||
|
public class FastCharBuffer extends FastBuffer implements CharSequence, Appendable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓冲集
|
||||||
|
*/
|
||||||
|
private char[][] buffers = new char[16][];
|
||||||
|
/**
|
||||||
|
* 当前缓冲
|
||||||
|
*/
|
||||||
|
private char[] currentBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*/
|
||||||
|
public FastCharBuffer() {
|
||||||
|
this(IoUtil.DEFAULT_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param size 一个缓冲区的最小字节数
|
||||||
|
*/
|
||||||
|
public FastCharBuffer(final int size) {
|
||||||
|
super(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向快速缓冲加入数据
|
||||||
|
*
|
||||||
|
* @param array 数据
|
||||||
|
* @param off 偏移量
|
||||||
|
* @param len 字节数
|
||||||
|
* @return 快速缓冲自身 @see FastByteBuffer
|
||||||
|
*/
|
||||||
|
public FastCharBuffer append(final char[] array, final int off, final int len) {
|
||||||
|
final int end = off + len;
|
||||||
|
if ((off < 0) || (len < 0) || (end > array.length)) {
|
||||||
|
throw new IndexOutOfBoundsException();
|
||||||
|
}
|
||||||
|
if (len == 0) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
final int newSize = size + len;
|
||||||
|
int remaining = len;
|
||||||
|
|
||||||
|
if (currentBuffer != null) {
|
||||||
|
// first try to fill current buffer
|
||||||
|
final 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);
|
||||||
|
|
||||||
|
// then copy remaining
|
||||||
|
// but this time we are sure that it will fit
|
||||||
|
final int part = Math.min(remaining, currentBuffer.length - offset);
|
||||||
|
System.arraycopy(array, end - remaining, currentBuffer, offset, part);
|
||||||
|
offset += part;
|
||||||
|
size += part;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向快速缓冲加入数据
|
||||||
|
*
|
||||||
|
* @param array 数据
|
||||||
|
* @return 快速缓冲自身 @see FastByteBuffer
|
||||||
|
*/
|
||||||
|
public FastCharBuffer append(final char[] array) {
|
||||||
|
return append(array, 0, array.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向快速缓冲加入一个字节
|
||||||
|
*
|
||||||
|
* @param element 一个字节的数据
|
||||||
|
* @return 快速缓冲自身 @see FastByteBuffer
|
||||||
|
*/
|
||||||
|
public FastCharBuffer append(final char element) {
|
||||||
|
if ((currentBuffer == null) || (offset == currentBuffer.length)) {
|
||||||
|
needNewBuffer(size + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentBuffer[offset] = element;
|
||||||
|
offset++;
|
||||||
|
size++;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将另一个快速缓冲加入到自身
|
||||||
|
*
|
||||||
|
* @param buff 快速缓冲
|
||||||
|
* @return 快速缓冲自身 @see FastByteBuffer
|
||||||
|
*/
|
||||||
|
public FastCharBuffer append(final FastCharBuffer buff) {
|
||||||
|
if (buff.size == 0) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < buff.currentBufferIndex; i++) {
|
||||||
|
append(buff.buffers[i]);
|
||||||
|
}
|
||||||
|
append(buff.currentBuffer, 0, buff.offset);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据索引位返回缓冲集中的缓冲
|
||||||
|
*
|
||||||
|
* @param index 索引位
|
||||||
|
* @return 缓冲
|
||||||
|
*/
|
||||||
|
public char[] array(final int index) {
|
||||||
|
return buffers[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
super.reset();
|
||||||
|
currentBuffer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回快速缓冲中的数据,如果缓冲区中的数据长度固定,则直接返回原始数组<br>
|
||||||
|
* 注意此方法共享数组,不能修改数组内容!
|
||||||
|
*
|
||||||
|
* @return 快速缓冲中的数据
|
||||||
|
*/
|
||||||
|
public char[] toArrayZeroCopyIfPossible() {
|
||||||
|
if (1 == currentBufferIndex) {
|
||||||
|
final int len = buffers[0].length;
|
||||||
|
if (len == size) {
|
||||||
|
return buffers[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回快速缓冲中的数据
|
||||||
|
*
|
||||||
|
* @return 快速缓冲中的数据
|
||||||
|
*/
|
||||||
|
public char[] toArray() {
|
||||||
|
return toArray(0, this.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回快速缓冲中的数据
|
||||||
|
*
|
||||||
|
* @param start 逻辑起始位置
|
||||||
|
* @param len 逻辑字节长
|
||||||
|
* @return 快速缓冲中的数据
|
||||||
|
*/
|
||||||
|
public char[] toArray(int start, int len) {
|
||||||
|
Assert.isTrue(start >= 0, "Start must be greater than zero!");
|
||||||
|
Assert.isTrue(len >= 0, "Length must be greater than zero!");
|
||||||
|
|
||||||
|
if (start >= this.size || len == 0) {
|
||||||
|
return new char[0];
|
||||||
|
}
|
||||||
|
if (len > (this.size - start)) {
|
||||||
|
len = this.size - start;
|
||||||
|
}
|
||||||
|
int remaining = len;
|
||||||
|
int pos = 0;
|
||||||
|
final char[] result = new char[len];
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (start >= buffers[i].length) {
|
||||||
|
start -= buffers[i].length;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i < buffersCount) {
|
||||||
|
final char[] buf = buffers[i];
|
||||||
|
final int bufLen = Math.min(buf.length - start, remaining);
|
||||||
|
System.arraycopy(buf, start, result, pos, bufLen);
|
||||||
|
pos += bufLen;
|
||||||
|
remaining -= bufLen;
|
||||||
|
if (remaining == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
start = 0;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据索引位返回一个字节
|
||||||
|
*
|
||||||
|
* @param index 索引位
|
||||||
|
* @return 一个字节
|
||||||
|
*/
|
||||||
|
public char get(int index) {
|
||||||
|
if ((index >= size) || (index < 0)) {
|
||||||
|
throw new IndexOutOfBoundsException();
|
||||||
|
}
|
||||||
|
int ndx = 0;
|
||||||
|
while (true) {
|
||||||
|
final char[] b = buffers[ndx];
|
||||||
|
if (index < b.length) {
|
||||||
|
return b[index];
|
||||||
|
}
|
||||||
|
ndx++;
|
||||||
|
index -= b.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new String(toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char charAt(final int index) {
|
||||||
|
return get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence subSequence(final int start, final int end) {
|
||||||
|
final int len = end - start;
|
||||||
|
return new StringBuilder(len).append(toArray(start, len));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FastCharBuffer append(final CharSequence csq) {
|
||||||
|
if(csq instanceof String){
|
||||||
|
return append((String)csq);
|
||||||
|
}
|
||||||
|
return append(csq, 0, csq.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends character sequence to buffer.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public FastCharBuffer append(final CharSequence csq, final int start, final int end) {
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
append(csq.charAt(i));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 追加字符串
|
||||||
|
*
|
||||||
|
* @param string String
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public FastCharBuffer append(final String string) {
|
||||||
|
final int len = string.length();
|
||||||
|
if (len == 0) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int newSize = size + len;
|
||||||
|
int remaining = len;
|
||||||
|
int start = 0;
|
||||||
|
|
||||||
|
if (currentBuffer != null) {
|
||||||
|
// first try to fill current buffer
|
||||||
|
final int part = Math.min(remaining, currentBuffer.length - offset);
|
||||||
|
string.getChars(0, part, currentBuffer, offset);
|
||||||
|
remaining -= part;
|
||||||
|
offset += part;
|
||||||
|
size += part;
|
||||||
|
start += part;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remaining > 0) {
|
||||||
|
// still some data left
|
||||||
|
// ask for new buffer
|
||||||
|
needNewBuffer(newSize);
|
||||||
|
|
||||||
|
// then copy remaining
|
||||||
|
// but this time we are sure that it will fit
|
||||||
|
final int part = Math.min(remaining, currentBuffer.length - offset);
|
||||||
|
string.getChars(start, start + part, currentBuffer, offset);
|
||||||
|
offset += part;
|
||||||
|
size += part;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void needNewBuffer(final int newSize) {
|
||||||
|
final int delta = newSize - size;
|
||||||
|
final int newBufferSize = Math.max(minChunkLen, delta);
|
||||||
|
|
||||||
|
currentBufferIndex++;
|
||||||
|
currentBuffer = new char[newBufferSize];
|
||||||
|
offset = 0;
|
||||||
|
|
||||||
|
// add buffer
|
||||||
|
if (currentBufferIndex >= buffers.length) {
|
||||||
|
final int newLen = buffers.length << 1;
|
||||||
|
final char[][] newBuffers = new char[newLen][];
|
||||||
|
System.arraycopy(buffers, 0, newBuffers, 0, buffers.length);
|
||||||
|
buffers = newBuffers;
|
||||||
|
}
|
||||||
|
buffers[currentBufferIndex] = currentBuffer;
|
||||||
|
buffersCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -93,7 +93,7 @@ public class FastByteArrayOutputStream extends OutputStream {
|
|||||||
* @return 长度
|
* @return 长度
|
||||||
*/
|
*/
|
||||||
public int size() {
|
public int size() {
|
||||||
return buffer.size();
|
return buffer.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -128,7 +128,7 @@ public class LineInputStream extends FilterInputStream implements Iterable<byte[
|
|||||||
} else if (CharUtil.LF == c) {
|
} else if (CharUtil.LF == c) {
|
||||||
// 非转义状态下,表示行的结束
|
// 非转义状态下,表示行的结束
|
||||||
// 如果换行符是`\r\n`,删除末尾的`\r`
|
// 如果换行符是`\r\n`,删除末尾的`\r`
|
||||||
final int lastIndex = out.size() - 1;
|
final int lastIndex = out.length() - 1;
|
||||||
if (lastIndex >= 0 && CharUtil.CR == out.get(lastIndex)) {
|
if (lastIndex >= 0 && CharUtil.CR == out.get(lastIndex)) {
|
||||||
return out.toArray(0, lastIndex);
|
return out.toArray(0, lastIndex);
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
@BenchmarkMode(Mode.AverageTime)//每次执行平均花费时间
|
@BenchmarkMode(Mode.AverageTime)//每次执行平均花费时间
|
||||||
@Warmup(iterations = 1, time = 1) //预热5次调用
|
@Warmup(iterations = 1, time = 1) //预热5次调用
|
||||||
@Measurement(iterations = 1, time = 5, timeUnit = TimeUnit.SECONDS) // 执行5此,每次1秒
|
@Measurement(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS) // 执行5此,每次1秒
|
||||||
@Threads(1) //单线程
|
@Threads(1) //单线程
|
||||||
@Fork(1) //
|
@Fork(1) //
|
||||||
@OutputTimeUnit(TimeUnit.NANOSECONDS) // 单位:纳秒
|
@OutputTimeUnit(TimeUnit.NANOSECONDS) // 单位:纳秒
|
||||||
@ -38,6 +38,12 @@ public class JsonToStringJmh {
|
|||||||
Assertions.assertNotNull(jsonStr);
|
Assertions.assertNotNull(jsonStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void gsonAppendJmh() {
|
||||||
|
final String jsonStr = gson.toString();
|
||||||
|
Assertions.assertNotNull(jsonStr);
|
||||||
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
public void hutoolJmh() {
|
public void hutoolJmh() {
|
||||||
final String jsonStr = hutoolJSON.toString();
|
final String jsonStr = hutoolJSON.toString();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user