Coverage Summary for Class: CharSequenceReader (com.google.common.io)

Class Class, % Method, % Line, %
CharSequenceReader 0% (0/1) 0% (0/13) 0% (0/47)


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  15 package com.google.common.io; 16  17 import static com.google.common.base.Preconditions.checkArgument; 18 import static com.google.common.base.Preconditions.checkNotNull; 19 import static com.google.common.base.Preconditions.checkPositionIndexes; 20 import static java.util.Objects.requireNonNull; 21  22 import com.google.common.annotations.GwtIncompatible; 23 import java.io.IOException; 24 import java.io.Reader; 25 import java.nio.CharBuffer; 26 import javax.annotation.CheckForNull; 27  28 /** 29  * A {@link Reader} that reads the characters in a {@link CharSequence}. Like {@code StringReader}, 30  * but works with any {@link CharSequence}. 31  * 32  * @author Colin Decker 33  */ 34 // TODO(cgdecker): make this public? as a type, or a method in CharStreams? 35 @GwtIncompatible 36 @ElementTypesAreNonnullByDefault 37 final class CharSequenceReader extends Reader { 38  39  @CheckForNull private CharSequence seq; 40  private int pos; 41  private int mark; 42  43  /** Creates a new reader wrapping the given character sequence. */ 44  public CharSequenceReader(CharSequence seq) { 45  this.seq = checkNotNull(seq); 46  } 47  48  private void checkOpen() throws IOException { 49  if (seq == null) { 50  throw new IOException("reader closed"); 51  } 52  } 53  54  private boolean hasRemaining() { 55  return remaining() > 0; 56  } 57  58  private int remaining() { 59  requireNonNull(seq); // safe as long as we call this only after checkOpen 60  return seq.length() - pos; 61  } 62  63  /* 64  * To avoid the need to call requireNonNull so much, we could consider more clever approaches, 65  * such as: 66  * 67  * - Make checkOpen return the non-null `seq`. Then callers can assign that to a local variable or 68  * even back to `this.seq`. However, that may suggest that we're defending against concurrent 69  * mutation, which is not an actual risk because we use `synchronized`. 70  * - Make `remaining` require a non-null `seq` argument. But this is a bit weird because the 71  * method, while it would avoid the instance field `seq` would still access the instance field 72  * `pos`. 73  */ 74  75  @Override 76  public synchronized int read(CharBuffer target) throws IOException { 77  checkNotNull(target); 78  checkOpen(); 79  requireNonNull(seq); // safe because of checkOpen 80  if (!hasRemaining()) { 81  return -1; 82  } 83  int charsToRead = Math.min(target.remaining(), remaining()); 84  for (int i = 0; i < charsToRead; i++) { 85  target.put(seq.charAt(pos++)); 86  } 87  return charsToRead; 88  } 89  90  @Override 91  public synchronized int read() throws IOException { 92  checkOpen(); 93  requireNonNull(seq); // safe because of checkOpen 94  return hasRemaining() ? seq.charAt(pos++) : -1; 95  } 96  97  @Override 98  public synchronized int read(char[] cbuf, int off, int len) throws IOException { 99  checkPositionIndexes(off, off + len, cbuf.length); 100  checkOpen(); 101  requireNonNull(seq); // safe because of checkOpen 102  if (!hasRemaining()) { 103  return -1; 104  } 105  int charsToRead = Math.min(len, remaining()); 106  for (int i = 0; i < charsToRead; i++) { 107  cbuf[off + i] = seq.charAt(pos++); 108  } 109  return charsToRead; 110  } 111  112  @Override 113  public synchronized long skip(long n) throws IOException { 114  checkArgument(n >= 0, "n (%s) may not be negative", n); 115  checkOpen(); 116  int charsToSkip = (int) Math.min(remaining(), n); // safe because remaining is an int 117  pos += charsToSkip; 118  return charsToSkip; 119  } 120  121  @Override 122  public synchronized boolean ready() throws IOException { 123  checkOpen(); 124  return true; 125  } 126  127  @Override 128  public boolean markSupported() { 129  return true; 130  } 131  132  @Override 133  public synchronized void mark(int readAheadLimit) throws IOException { 134  checkArgument(readAheadLimit >= 0, "readAheadLimit (%s) may not be negative", readAheadLimit); 135  checkOpen(); 136  mark = pos; 137  } 138  139  @Override 140  public synchronized void reset() throws IOException { 141  checkOpen(); 142  pos = mark; 143  } 144  145  @Override 146  public synchronized void close() throws IOException { 147  seq = null; 148  } 149 }