pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / contrib / benchmark / src / java / org / apache / lucene / benchmark / byTask / utils / StringBuilderReader.java
1 package org.apache.lucene.benchmark.byTask.utils;
2
3 /**
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.
7  * The ASF licenses this file to You under the Apache License, Version 2.0
8  * (the "License"); you may not use this file except in compliance with
9  * the License.  You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import java.io.IOException;
21 import java.io.Reader;
22
23 /**
24  * Implements a {@link Reader} over a {@link StringBuilder} instance. Although
25  * one can use {@link java.io.StringReader} by passing it
26  * {@link StringBuilder#toString()}, it is better to use this class, as it
27  * doesn't mark the passed-in {@link StringBuilder} as shared (which will cause
28  * inner char[] allocations at the next append() attempt).<br>
29  * Notes:
30  * <ul>
31  * <li>This implementation assumes the underlying {@link StringBuilder} is not
32  * changed during the use of this {@link Reader} implementation.
33  * <li>This implementation is thread-safe.
34  * <li>The implementation looks very much like {@link java.io.StringReader} (for
35  * the right reasons).
36  * <li>If one wants to reuse that instance, then the following needs to be done:
37  * <pre>
38  * StringBuilder sb = new StringBuilder("some text");
39  * Reader reader = new StringBuilderReader(sb);
40  * ... read from reader - don't close it ! ...
41  * sb.setLength(0);
42  * sb.append("some new text");
43  * reader.reset();
44  * ... read the new string from the reader ...
45  * </pre>
46  * </ul>
47  */
48 public class StringBuilderReader extends Reader {
49   
50   // The StringBuilder to read from.
51   private StringBuilder sb;
52
53   // The length of 'sb'.
54   private int length;
55
56   // The next position to read from the StringBuilder.
57   private int next = 0;
58
59   // The mark position. The default value 0 means the start of the text.
60   private int mark = 0;
61
62   public StringBuilderReader(StringBuilder sb) {
63     set(sb);
64   }
65
66   /** Check to make sure that the stream has not been closed. */
67   private void ensureOpen() throws IOException {
68     if (sb == null) {
69       throw new IOException("Stream has already been closed");
70     }
71   }
72
73   @Override
74   public void close() {
75     synchronized (lock) {
76       sb = null;
77     }
78   }
79
80   /**
81    * Mark the present position in the stream. Subsequent calls to reset() will
82    * reposition the stream to this point.
83    * 
84    * @param readAheadLimit Limit on the number of characters that may be read
85    *        while still preserving the mark. Because the stream's input comes
86    *        from a StringBuilder, there is no actual limit, so this argument 
87    *        must not be negative, but is otherwise ignored.
88    * @exception IllegalArgumentException If readAheadLimit is < 0
89    * @exception IOException If an I/O error occurs
90    */
91   @Override
92   public void mark(int readAheadLimit) throws IOException {
93     if (readAheadLimit < 0){
94       throw new IllegalArgumentException("Read-ahead limit cannpt be negative: " + readAheadLimit);
95     }
96     synchronized (lock) {
97       ensureOpen();
98       mark = next;
99     }
100   }
101
102   @Override
103   public boolean markSupported() {
104     return true;
105   }
106
107   @Override
108   public int read() throws IOException {
109     synchronized (lock) {
110       ensureOpen();
111       return next >= length ? -1 : sb.charAt(next++);
112     }
113   }
114
115   @Override
116   public int read(char cbuf[], int off, int len) throws IOException {
117     synchronized (lock) {
118       ensureOpen();
119
120       // Validate parameters
121       if (off < 0 || off > cbuf.length || len < 0 || off + len > cbuf.length) {
122         throw new IndexOutOfBoundsException("off=" + off + " len=" + len + " cbuf.length=" + cbuf.length);
123       }
124
125       if (len == 0) {
126         return 0;
127       }
128
129       if (next >= length) {
130         return -1;
131       }
132
133       int n = Math.min(length - next, len);
134       sb.getChars(next, next + n, cbuf, off);
135       next += n;
136       return n;
137     }
138   }
139
140   @Override
141   public boolean ready() throws IOException {
142     synchronized (lock) {
143       ensureOpen();
144       return true;
145     }
146   }
147
148   @Override
149   public void reset() throws IOException {
150     synchronized (lock) {
151       ensureOpen();
152       next = mark;
153       length = sb.length();
154     }
155   }
156
157   public void set(StringBuilder sb) {
158     synchronized (lock) {
159       this.sb = sb;
160       length = sb.length();
161       next = mark = 0;
162     }
163   }
164   
165   @Override
166   public long skip(long ns) throws IOException {
167     synchronized (lock) {
168       ensureOpen();
169       if (next >= length) {
170         return 0;
171       }
172
173       // Bound skip by beginning and end of the source
174       long n = Math.min(length - next, ns);
175       n = Math.max(-next, n);
176       next += n;
177       return n;
178     }
179   }
180
181 }