mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 14:24:46 +02:00
8341566: Add Reader.of(CharSequence)
Reviewed-by: rriggs, jpai, liach, alanb
This commit is contained in:
parent
b0ac633b2d
commit
3c14c2babb
3 changed files with 349 additions and 47 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -140,6 +140,119 @@ public abstract class Reader implements Readable, Closeable {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Reader} that reads characters from a
|
||||
* {@code CharSequence}. The reader is initially open and reading starts at
|
||||
* the first character in the sequence.
|
||||
*
|
||||
* <p> The returned reader supports the {@link #mark mark()} and
|
||||
* {@link #reset reset()} operations.
|
||||
*
|
||||
* <p> The resulting reader is not safe for use by multiple
|
||||
* concurrent threads. If the reader is to be used by more than one
|
||||
* thread it should be controlled by appropriate synchronization.
|
||||
*
|
||||
* <p> If the sequence changes while the reader is open, e.g. the length
|
||||
* changes, the behavior is undefined.
|
||||
*
|
||||
* @param cs {@code CharSequence} providing the character stream.
|
||||
* @return a {@code Reader} which reads characters from {@code cs}
|
||||
* @throws NullPointerException if {@code cs} is {@code null}
|
||||
*
|
||||
* @since 24
|
||||
*/
|
||||
public static Reader of(final CharSequence cs) {
|
||||
Objects.requireNonNull(cs);
|
||||
|
||||
return new Reader() {
|
||||
private boolean isClosed;
|
||||
private int next = 0;
|
||||
private int mark = 0;
|
||||
|
||||
/** Check to make sure that the stream has not been closed */
|
||||
private void ensureOpen() throws IOException {
|
||||
if (isClosed)
|
||||
throw new IOException("Stream closed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
ensureOpen();
|
||||
if (next >= cs.length())
|
||||
return -1;
|
||||
return cs.charAt(next++);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(char[] cbuf, int off, int len) throws IOException {
|
||||
ensureOpen();
|
||||
Objects.checkFromIndexSize(off, len, cbuf.length);
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
int length = cs.length();
|
||||
if (next >= length)
|
||||
return -1;
|
||||
int n = Math.min(length - next, len);
|
||||
switch (cs) {
|
||||
case String s -> s.getChars(next, next + n, cbuf, off);
|
||||
case StringBuilder sb -> sb.getChars(next, next + n, cbuf, off);
|
||||
case StringBuffer sb -> sb.getChars(next, next + n, cbuf, off);
|
||||
case CharBuffer cb -> cb.get(next, cbuf, off, n);
|
||||
default -> {
|
||||
for (int i = 0; i < n; i++)
|
||||
cbuf[off + i] = cs.charAt(next + i);
|
||||
}
|
||||
}
|
||||
next += n;
|
||||
return n;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
ensureOpen();
|
||||
if (next >= cs.length())
|
||||
return 0;
|
||||
// Bound skip by beginning and end of the source
|
||||
long r = Math.min(cs.length() - next, n);
|
||||
r = Math.max(-next, r);
|
||||
next += (int)r;
|
||||
return r;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ready() throws IOException {
|
||||
ensureOpen();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mark(int readAheadLimit) throws IOException {
|
||||
if (readAheadLimit < 0){
|
||||
throw new IllegalArgumentException("Read-ahead limit < 0");
|
||||
}
|
||||
ensureOpen();
|
||||
mark = next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() throws IOException {
|
||||
ensureOpen();
|
||||
next = mark;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
isClosed = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The object used to synchronize operations on this stream. For
|
||||
* efficiency, a character-stream object may use an object other than
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -30,16 +30,17 @@ import java.util.Objects;
|
|||
/**
|
||||
* A character stream whose source is a string.
|
||||
*
|
||||
* @apiNote
|
||||
* {@link Reader#of(CharSequence)} provides a method to read from any
|
||||
* {@link CharSequence} that may be more efficient than {@code StringReader}.
|
||||
*
|
||||
* @author Mark Reinhold
|
||||
* @since 1.1
|
||||
*/
|
||||
|
||||
public class StringReader extends Reader {
|
||||
|
||||
private final int length;
|
||||
private String str;
|
||||
private int next = 0;
|
||||
private int mark = 0;
|
||||
private final Reader r;
|
||||
|
||||
/**
|
||||
* Creates a new string reader.
|
||||
|
@ -47,14 +48,7 @@ public class StringReader extends Reader {
|
|||
* @param s String providing the character stream.
|
||||
*/
|
||||
public StringReader(String s) {
|
||||
this.length = s.length();
|
||||
this.str = s;
|
||||
}
|
||||
|
||||
/** Check to make sure that the stream has not been closed */
|
||||
private void ensureOpen() throws IOException {
|
||||
if (str == null)
|
||||
throw new IOException("Stream closed");
|
||||
r = Reader.of(s);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -67,10 +61,7 @@ public class StringReader extends Reader {
|
|||
*/
|
||||
public int read() throws IOException {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
if (next >= length)
|
||||
return -1;
|
||||
return str.charAt(next++);
|
||||
return r.read();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,17 +85,7 @@ public class StringReader extends Reader {
|
|||
*/
|
||||
public int read(char[] cbuf, int off, int len) throws IOException {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
Objects.checkFromIndexSize(off, len, cbuf.length);
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (next >= length)
|
||||
return -1;
|
||||
int n = Math.min(length - next, len);
|
||||
str.getChars(next, next + n, cbuf, off);
|
||||
next += n;
|
||||
return n;
|
||||
return r.read(cbuf, off, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,14 +111,7 @@ public class StringReader extends Reader {
|
|||
*/
|
||||
public long skip(long n) throws IOException {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
if (next >= length)
|
||||
return 0;
|
||||
// Bound skip by beginning and end of the source
|
||||
long r = Math.min(length - next, n);
|
||||
r = Math.max(-next, r);
|
||||
next += (int)r;
|
||||
return r;
|
||||
return r.skip(n);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,8 +124,7 @@ public class StringReader extends Reader {
|
|||
*/
|
||||
public boolean ready() throws IOException {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
return true;
|
||||
return r.ready();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,12 +149,8 @@ public class StringReader extends Reader {
|
|||
* @throws IOException If an I/O error occurs
|
||||
*/
|
||||
public void mark(int readAheadLimit) throws IOException {
|
||||
if (readAheadLimit < 0){
|
||||
throw new IllegalArgumentException("Read-ahead limit < 0");
|
||||
}
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
mark = next;
|
||||
r.mark(readAheadLimit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -193,8 +162,7 @@ public class StringReader extends Reader {
|
|||
*/
|
||||
public void reset() throws IOException {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
next = mark;
|
||||
r.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,7 +175,11 @@ public class StringReader extends Reader {
|
|||
*/
|
||||
public void close() {
|
||||
synchronized (lock) {
|
||||
str = null;
|
||||
try {
|
||||
r.close();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue