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

cn.wjybxx.dson.text.AbstractCharStream Maven / Gradle / Ivy

There is a newer version: 2.2.0
Show newest version
/*
 * Copyright 2023-2024 wjybxx([email protected])
 *
 * 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 cn.wjybxx.dson.text;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author wjybxx
 * date - 2023/6/5
 */
public abstract class AbstractCharStream implements DsonCharStream {

    private final List lines = new ArrayList<>();
    private LineInfo curLine;
    private boolean readingContent = false;
    private int position = -1;
    private boolean eof = false;

    public AbstractCharStream() {
    }

    /** 应该只在初始化时使用 */
    protected final void setPosition(int position) {
        this.position = position;
    }

    protected final void addLine(LineInfo lineInfo) {
        Objects.requireNonNull(lineInfo);
        lines.add(lineInfo);
    }

    @Override
    public int read() {
        if (isClosed()) throw new DsonParseException("Trying to read after closed");
        if (eof) throw new DsonParseException("Trying to read past eof");

        LineInfo curLine = this.curLine;
        if (curLine == null) {
            if (lines.isEmpty() && !scanNextLine()) {
                eof = true;
                return -1;
            }
            curLine = lines.get(0);
            onReadNextLine(curLine);
            return -2;
        }
        // 到达当前扫描部分的尾部,扫描更多的字符 - 不测试readingContent也没问题
        if (position == curLine.endPos && !curLine.isScanCompleted()) {
            scanMoreChars(curLine); // 要么读取到一个输入,要么行扫描完毕
            assert position < curLine.endPos || curLine.isScanCompleted();
        }
        if (curLine.isScanCompleted()) {
            if (readingContent) {
                if (position >= curLine.lastReadablePosition()) { // 读完或已在行尾(unread)
                    return onReadEndOfLine(curLine);
                } else {
                    position++;
                }
            } else if (curLine.hasContent()) {
                readingContent = true;
            } else {
                return onReadEndOfLine(curLine);
            }
        } else {
            if (readingContent) {
                position++;
            } else {
                readingContent = true;
            }
        }
        return charAt(curLine, position);
    }

    private int onReadEndOfLine(LineInfo curLine) {
        // 这里不可以修改position,否则unread可能出错
        if (curLine.state == LineInfo.STATE_EOF) {
            eof = true;
            return -1;
        }
        int index = indexOfCurLine(lines, curLine);
        if (index + 1 == lines.size() && !scanNextLine()) {
            eof = true;
            return -1;
        }
        curLine = lines.get(index + 1);
        onReadNextLine(curLine);
        return -2;
    }

    private void onReadNextLine(LineInfo nextLine) {
        assert nextLine.isScanCompleted() || nextLine.hasContent();
        this.curLine = nextLine;
        this.readingContent = false;
        this.position = nextLine.startPos;
        discardReadLines(lines, nextLine); // 清除部分缓存
    }

    private void onBackToPreLine(LineInfo preLine) {
        assert preLine.isScanCompleted();
        this.curLine = preLine;
        if (preLine.hasContent()) {
            // 有内容的情况下,需要回退到上一行最后一个字符的位置,否则继续unread会出错
            this.position = preLine.lastReadablePosition();
            this.readingContent = true;
        } else {
            // 无内容的情况下回退到startPos,和read保持一致
            this.position = preLine.startPos;
            this.readingContent = false;
        }
    }

    @Override
    public int unread() {
        if (eof) {
            eof = false;
            return -1;
        }
        LineInfo curLine = this.curLine;
        if (curLine == null) {
            throw new IllegalStateException("read must be called before unread.");
        }
        // 当前行回退 -- 需要检测是否回退到bufferStartPos之前
        if (readingContent) {
            if (position > curLine.startPos) {
                checkUnreadOverFlow(position - 1);
                position--;
            } else {
                readingContent = false;
            }
            return 0;
        }
        // 尝试回退到上一行,需要检测上一行的最后一个可读字符是否溢出
        int index = indexOfCurLine(lines, curLine);
        if (index > 0) {
            LineInfo preLine = lines.get(index - 1);
            if (preLine.hasContent()) {
                checkUnreadOverFlow(preLine.lastReadablePosition());
            } else {
                checkUnreadOverFlow(preLine.startPos);
            }
            onBackToPreLine(preLine);
            return -2;
        } else {
            if (curLine.ln != getFirstLn()) {
                throw bufferOverFlow(position);
            }
            // 回退到初始状态
            this.curLine = null;
            this.readingContent = false;
            this.position = -1;
            return 0;
        }
    }

    @Override
    public void skipLine() {
        LineInfo curLine = this.curLine;
        if (curLine == null) throw new IllegalStateException();
        while (!curLine.isScanCompleted()) {
            position = curLine.endPos;
            scanMoreChars(curLine);
        }
        if (curLine.hasContent()) {
            readingContent = true;
            position = curLine.lastReadablePosition();
        }
    }

    @Override
    public int getPosition() {
        return position;
    }

    @Override
    public LineInfo getCurLine() {
        return curLine;
    }

    //

    protected static int indexOfCurLine(List lines, LineInfo curLine) {
        return curLine.ln - lines.get(0).ln;
    }

    protected static DsonParseException bufferOverFlow(int position) {
        return new DsonParseException("BufferOverFlow, caused by unread, pos: " + position);
    }

    protected boolean isReadingContent() {
        return readingContent;
    }

    protected boolean isEof() {
        return eof;
    }

    /** 获取首行行号,基于Reader时可能不是第一行开始 */
    protected int getFirstLn() {
        return 1;
    }

    /** 丢弃部分已读的行,减少内存占用 */
    protected void discardReadLines(List lines, LineInfo curLine) {
        if (curLine == null) {
            return;
        }
        int idx = indexOfCurLine(lines, curLine);
        if (idx >= 10) {
            lines.subList(0, 5).clear();
        }
    }

    /** 当前流是否已处于关闭状态 */
    protected abstract boolean isClosed();

    /** 获取指定全局位置的字符 */
    protected abstract int charAt(LineInfo curLine, int position);

    /**
     * 检测是否可以回退到指定位置
     *
     * @throws DsonParseException 如果不可回退到指定位置
     */
    protected abstract void checkUnreadOverFlow(int position);

    /**
     * @param line 要扫描的行,可能是当前行,也可能是下一行
     * @throws DsonParseException 如果缓冲区已满
     * @apiNote 要么读取到一个输入,要么行扫描完毕
     */
    protected abstract void scanMoreChars(LineInfo line);

    /** @return 如果扫描到新的一行则返回true */
    protected abstract boolean scanNextLine();

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy