Search

2025-02-15

상태 머신 모호성 해결
LAST_LINE 상태 모호성 발생.
LAST_LINE의 의미의 경우 코드를 읽는 입장에서 마지막 CSV Record로 인식할 수 있음.
하지만 실질적으로 buf 내에 row ≥ 1이 될 수 있음.
그렇기에 LAST_LINE의 상태 보다는 (LAST_DATA, LAST_LINE | LAST_RECORD)로 세분화가 좋다고 판단됨.
LAST_DATA의 경우 현 LAST_LINE의 기능을 그대로 사용.
LAST_LINE | LAST_RECORD 의 경우 delimiter 유무에 따라 LAST_DATA 에서 전이됨.
실질적으로 마지막에 false 반환은 EOF로 끝날 예정.
package parserTest3; import lombok.AccessLevel; import lombok.Getter; import java.io.IOException; import java.io.Reader; import java.io.UncheckedIOException; import java.util.Optional; import java.util.function.Function; import java.util.stream.Stream; @Getter public class InternalBuffer2 { @Getter(AccessLevel.NONE) private final Reader reader; private static final int DEFAULT_BUFFER_SIZE = 8192; private static final int READ_SIZE = DEFAULT_BUFFER_SIZE; private BufferState state = BufferState.INITIAL; private char[] buf = new char[DEFAULT_BUFFER_SIZE]; private int pos, begin, limit; private enum BufferState { INITIAL, PROGRESSING, EXTEND, RELOCATE, LAST_DATA, LAST_LINE, EOF; } public InternalBuffer2(Reader reader) { this.reader = reader; } /** * TODO isLastLine 추가 * RecordParser내에서 마지막 줄 여부 판단을 위해서 필요함 * <p> * 상태 전이 [] 반복, () 선택, {} 종료 * INITIAL -> [PROGRESSING <-> (EXTEND | RELOCATE)] -> LAST_DATA -> LAST_LINE -> EOF {종료} * -> EOF {종료} */ boolean fill() { switch (state) { case INITIAL: int cnt = read(buf, pos, READ_SIZE); if (cnt == -1) { return false; } state = BufferState.PROGRESSING; limit += cnt; return true; case PROGRESSING: /** * if -> begin >= limit 일 경우 즉, 커서가 끝까지 갔는데 아무 변화 없을때 * state = (pos == 0) ? EXTEND : RELOCATE; * continue; * retrun true; */ if (begin >= limit) { state = pos == 0 ? BufferState.EXTEND : BufferState.RELOCATE; } return true; case EXTEND: /** * 확장 및 read * extend() 확장 * cnt = read(begin) -> READ_SIZE 만큼 읽기 * if -> cnt == -1 LAST_LINE * else -> PROGRESSING and limit += cnt * continue; */ extendAndLoad(); return true; case RELOCATE: /** * 재배치 및 read * relocate() * begin = limit - pos; * pos = 0; * cnt = read(begin) // READ_SIZE 만큼 데이터 로드 * if -> cnt == -1 LAST_LINE * else -> PROGRESSING */ relocateAndLoad(); return true; case LAST_DATA: if (pos < limit) { state = BufferState.LAST_LINE; return true; } state = BufferState.EOF; return true; case LAST_LINE: state = BufferState.EOF; return true; case EOF: default: return false; } } boolean isLastLine() { return state == BufferState.LAST_LINE; } static <T, R> Optional<Function<T, R>> ifLastRowOrElse(InternalBuffer2 buffer, Function<T, R> action, Function<T, R> elseAction) { if (buffer.getPos() == buffer.getLimit()) { return Optional.empty(); } boolean isLastLine = buffer.getState() == BufferState.LAST_LINE && buffer.getPos() < buffer.getLimit(); return Optional.of(isLastLine ? action : elseAction); } char getBeginAndIncrement() { return buf[begin++]; } void setPos(int newPos) { this.pos = newPos; } boolean notBeginAtLimit() { return begin < limit; } private int read(char[] buf, int off, int len) { try { return reader.read(buf, off, len); } catch (IOException e) { throw new UncheckedIOException(e); } } private void extendAndLoad() { // TODO max size 예외처리 char[] newBuf = new char[buf.length * 2]; System.arraycopy(buf, 0, newBuf, 0, buf.length); buf = newBuf; int cnt = read(buf, begin, READ_SIZE); stateAndLimitUpdate(cnt, limit + cnt); } private void relocateAndLoad() { final int copyLength = begin - pos; System.arraycopy(buf, pos, buf, 0, copyLength); int cnt = read(buf, copyLength, READ_SIZE - copyLength); pos = 0; begin = copyLength; stateAndLimitUpdate(cnt, copyLength + cnt); } private void stateAndLimitUpdate(int readSize, int newLimit) { state = readSize == -1 ? BufferState.LAST_DATA : BufferState.PROGRESSING; limit = readSize == -1 ? begin : newLimit; } }
JavaScript
복사