Skip to content

Commit 35ebaea

Browse files
committed
Implement FileHandle.readline.
1 parent 4204202 commit 35ebaea

File tree

1 file changed

+65
-10
lines changed

1 file changed

+65
-10
lines changed

src/vm/jvm/runtime/org/perl6/nqp/io/FileHandle.java

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public class FileHandle implements IIOClosable, IIOSeekable, IIOEncodable, IIOSy
2020
private CharsetEncoder enc;
2121
private CharsetDecoder dec;
2222
private boolean eof = false;
23+
private ByteBuffer readBuffer;
2324

2425
public FileHandle(ThreadContext tc, String filename, String mode) {
2526
try {
@@ -86,34 +87,88 @@ public void setEncoding(ThreadContext tc, Charset cs) {
8687
dec = cs.newDecoder();
8788
}
8889

89-
public String slurp(ThreadContext tc) {
90+
public synchronized String slurp(ThreadContext tc) {
9091
try {
9192
// Read in file.
9293
ArrayList<ByteBuffer> buffers = new ArrayList<ByteBuffer>();
9394
ByteBuffer curBuffer = ByteBuffer.allocate(32768);
9495
int total = 0;
9596
int read;
97+
if (readBuffer != null) {
98+
buffers.add(ByteBuffer.wrap(readBuffer.array(), readBuffer.position(),
99+
readBuffer.limit() - readBuffer.position()));
100+
readBuffer = null;
101+
}
96102
while ((read = chan.read(curBuffer)) != -1) {
103+
curBuffer.flip();
97104
buffers.add(curBuffer);
98105
curBuffer = ByteBuffer.allocate(32768);
99106
total += read;
100107
}
101108
eof = true;
102109

103-
// Copy to a single buffer and decode (could be smarter, but need
104-
// to be wary as UTF-8 chars may span a buffer boundary).
105-
ByteBuffer allBytes = ByteBuffer.allocate(total);
106-
for (ByteBuffer bb : buffers)
107-
allBytes.put(bb.array(), 0, bb.position());
108-
allBytes.rewind();
109-
return dec.decode(allBytes).toString();
110+
return decodeBuffers(buffers, total);
111+
} catch (IOException e) {
112+
throw ExceptionHandling.dieInternal(tc, e);
113+
}
114+
}
115+
116+
public synchronized String readline(ThreadContext tc) {
117+
try {
118+
boolean foundLine = false;
119+
ArrayList<ByteBuffer> lineChunks = new ArrayList<ByteBuffer>();
120+
int total = 0;
121+
122+
while (!foundLine) {
123+
/* Ensure we have a buffer available. */
124+
if (readBuffer == null) {
125+
readBuffer = ByteBuffer.allocate(32768);
126+
if (chan.read(readBuffer) == -1) {
127+
/* End of file, so what we have is fine. */
128+
eof = true;
129+
foundLine = true;
130+
break;
131+
}
132+
readBuffer.flip();
133+
}
134+
135+
/* Look for a line end. */
136+
int start = readBuffer.position();
137+
int end = start;
138+
while (!foundLine && end < readBuffer.limit()) {
139+
if (readBuffer.get(end) == '\n')
140+
foundLine = true;
141+
end++;
142+
}
143+
144+
/* Copy what we found into the results. */
145+
byte[] lineBytes = new byte[end - start];
146+
readBuffer.get(lineBytes);
147+
lineChunks.add(ByteBuffer.wrap(lineBytes));
148+
total += lineBytes.length;
149+
150+
/* If we didn't find a line, will cross chunk boundary. */
151+
if (!foundLine)
152+
readBuffer = null;
153+
}
154+
155+
if (lineChunks.size() == 1)
156+
return dec.decode(lineChunks.get(0)).toString();
157+
else
158+
return decodeBuffers(lineChunks, total);
110159
} catch (IOException e) {
111160
throw ExceptionHandling.dieInternal(tc, e);
112161
}
113162
}
114163

115-
public String readline(ThreadContext tc) {
116-
throw new RuntimeException("FileHandle.readline() NYI");
164+
private String decodeBuffers(ArrayList<ByteBuffer> buffers, int total) throws IOException {
165+
// Copy to a single buffer and decode (could be smarter, but need
166+
// to be wary as UTF-8 chars may span a buffer boundary).
167+
ByteBuffer allBytes = ByteBuffer.allocate(total);
168+
for (ByteBuffer bb : buffers)
169+
allBytes.put(bb.array(), 0, bb.limit());
170+
allBytes.rewind();
171+
return dec.decode(allBytes).toString();
117172
}
118173

119174
public boolean eof(ThreadContext tc) {

0 commit comments

Comments
 (0)