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