• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.io;
18 
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21 import static com.google.common.base.Preconditions.checkPositionIndexes;
22 
23 import java.io.IOException;
24 import java.io.Reader;
25 import java.nio.CharBuffer;
26 
27 /**
28  * A {@link Reader} that reads the characters in a {@link CharSequence}. Like {@code StringReader},
29  * but works with any {@link CharSequence}.
30  *
31  * @author Colin Decker
32  */
33 // TODO(user): make this public? as a type, or a method in CharStreams?
34 final class CharSequenceReader extends Reader {
35 
36   private CharSequence seq;
37   private int pos;
38   private int mark;
39 
40   /**
41    * Creates a new reader wrapping the given character sequence.
42    */
CharSequenceReader(CharSequence seq)43   public CharSequenceReader(CharSequence seq) {
44     this.seq = checkNotNull(seq);
45   }
46 
checkOpen()47   private void checkOpen() throws IOException {
48     if (seq == null) {
49       throw new IOException("reader closed");
50     }
51   }
52 
hasRemaining()53   private boolean hasRemaining() {
54     return remaining() > 0;
55   }
56 
remaining()57   private int remaining() {
58     return seq.length() - pos;
59   }
60 
61   @Override
read(CharBuffer target)62   public synchronized int read(CharBuffer target) throws IOException {
63     checkNotNull(target);
64     checkOpen();
65     if (!hasRemaining()) {
66       return -1;
67     }
68     int charsToRead = Math.min(target.remaining(), remaining());
69     for (int i = 0; i < charsToRead; i++) {
70       target.put(seq.charAt(pos++));
71     }
72     return charsToRead;
73   }
74 
75   @Override
read()76   public synchronized int read() throws IOException {
77     checkOpen();
78     return hasRemaining() ? seq.charAt(pos++) : -1;
79   }
80 
81   @Override
read(char[] cbuf, int off, int len)82   public synchronized int read(char[] cbuf, int off, int len) throws IOException {
83     checkPositionIndexes(off, off + len, cbuf.length);
84     checkOpen();
85     if (!hasRemaining()) {
86       return -1;
87     }
88     int charsToRead = Math.min(len, remaining());
89     for (int i = 0; i < charsToRead; i++) {
90       cbuf[off + i] = seq.charAt(pos++);
91     }
92     return charsToRead;
93   }
94 
95   @Override
skip(long n)96   public synchronized long skip(long n) throws IOException {
97     checkArgument(n >= 0, "n (%s) may not be negative", n);
98     checkOpen();
99     int charsToSkip = (int) Math.min(remaining(), n); // safe because remaining is an int
100     pos += charsToSkip;
101     return charsToSkip;
102   }
103 
104   @Override
ready()105   public synchronized boolean ready() throws IOException {
106     checkOpen();
107     return true;
108   }
109 
110   @Override
markSupported()111   public boolean markSupported() {
112     return true;
113   }
114 
115   @Override
mark(int readAheadLimit)116   public synchronized void mark(int readAheadLimit) throws IOException {
117     checkArgument(readAheadLimit >= 0, "readAheadLimit (%s) may not be negative", readAheadLimit);
118     checkOpen();
119     mark = pos;
120   }
121 
122   @Override
reset()123   public synchronized void reset() throws IOException {
124     checkOpen();
125     pos = mark;
126   }
127 
128   @Override
close()129   public synchronized void close() throws IOException {
130     seq = null;
131   }
132 }
133