All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.xceptance.common.io.XltBufferedLineReader Maven / Gradle / Ivy

Go to download

XLT (Xceptance LoadTest) is an extensive load and performance test tool developed and maintained by Xceptance.

There is a newer version: 8.4.1
Show newest version
/*
 * Copyright (c) 2005-2023 Xceptance Software Technologies GmbH
 *
 * 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 com.xceptance.common.io;

import java.io.Closeable;
import java.io.IOException;
import java.io.Reader;

import com.xceptance.xlt.api.util.XltCharBuffer;

/**
 * This class combines a BufferedReader and an OpenStringBuilder to keep the read and copy effort low. This class got
 * inspired by the BufferedReader from the JDK as well as the BufferedReader from Android. It is a rewrite to parse the
 * stream correctly and efficiently.
 *
 * @author Rene Schwietzke
 * @since 7.0.0
 */
public class XltBufferedLineReader implements Closeable
{
    // where to read out data from
    private Reader reader;

    // the buffer with the data from disk, we try to always have
    // the guarantee to read from the start, when we refill, we will
    // reset it in a way that we start from the beginning again
    private char[] buffer;

    // last read buffer pos
    private int bufferPos;

    // real buffer length
    private int bufferLength;

    // follow the JDK 21 change to set this to 16k by default
    private static final int BUFFERSIZE = 2 * 8192;

    // in case we read a \r, we might have to skip the following \n
    private boolean skipNL = false;

    private boolean eof = false;

    public XltBufferedLineReader(final Reader reader)
    {
        this.reader = reader;
        this.buffer = new char[BUFFERSIZE];
    }

    public XltBufferedLineReader(final Reader reader, final int bufferSize)
    {
        this.reader = reader;
        this.buffer = new char[bufferSize];
    }

    @Override
    public void close() throws IOException
    {
        if (reader != null)
        {
            reader.close();
        }
    }

    /**
     * Fill the buffer
     *
     * @return how much we read
     * @throws IOException
     */
    private int fill() throws IOException
    {
        // we can read the entire array
        bufferPos = 0;

        // read until we got something or reached end
        int read = 0;
        do
        {
            read = reader.read(buffer);
        }
        while (read == 0);

        return bufferLength = read;
    }

    /**
     * Our readline part
     * 
     * @throws IOException
     */
    public XltCharBuffer readLine() throws IOException
    {
        if (eof)
        {
            return null;
        }

        char[] sb = null;
        int lastFill = 0;
        int start = bufferPos;
        int sbLength = 0;

        for (;;)
        {
            if (bufferPos == bufferLength)
            {
                lastFill = fill();
                start = 0;
            }

            if (lastFill == -1)
            {
                // end reached
                eof = true;

                // save the rest
                return sb == null ? null : new XltCharBuffer(sb, 0, sbLength);
            }

            // do we have to skip a newline?
            if (skipNL && buffer[bufferPos] == '\n')
            {
                start = ++bufferPos;
            }
            skipNL = false;

            // run till we have a '\r'
            boolean eol = false;
            int i;
            for (i = bufferPos; i < bufferLength; i++)
            {
                final char c = buffer[i];
                if (c <= '\r') // help to save comparisons
                {
                    if (c == '\r')
                    {
                        skipNL = eol = true;
                        break;
                    }
                    if (c == '\n')
                    {
                        eol = true;
                        break;
                    }
                }
            }
            bufferPos = i;
            final int l = i - start;

            if (eol)
            {
                sb = append(buffer, start, l, sb, sbLength, l);
                sbLength = sbLength + l;
                bufferPos++;

                return new XltCharBuffer(sb, 0, sbLength);
            }
            else if (start < bufferPos)
            {
                // buffer empty and not end in sight
                // save what we have
                sb = append(buffer, start, l, sb, sbLength, 80);
                sbLength = sbLength + l;
            }
        }
    }

    /**
     * Append the char to the buffer and return it or create a new and copy the data and return that.
     *
     * @param start
     *            starting position inclusive
     * @param end
     *            end position exclusive
     * @return the array with the appended data, either new or the old
     */
    private static char[] append(char[] src, final int start, final int length, char[] dest, final int currentLength,
                                 final int initialCapacity)
    {
        if (dest == null)
        {
            dest = new char[Math.max(initialCapacity, length)];
            System.arraycopy(src, start, dest, 0, length);

            return dest;
        }

        if (length > 0)
        {
            final int newLength = currentLength + length;
            if (newLength > dest.length)
            {
                // grow
                final char[] old = dest;
                dest = new char[newLength * 2];
                System.arraycopy(old, 0, dest, 0, currentLength);
            }
            System.arraycopy(src, start, dest, currentLength, length);
        }

        return dest;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy