pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / src / java / org / apache / lucene / util / CharacterUtils.java
1 package org.apache.lucene.util;
2
3 import java.io.IOException;
4 import java.io.Reader;
5
6 /**
7  * Licensed to the Apache Software Foundation (ASF) under one or more
8  * contributor license agreements.  See the NOTICE file distributed with
9  * this work for additional information regarding copyright ownership.
10  * The ASF licenses this file to You under the Apache License, Version 2.0
11  * (the "License"); you may not use this file except in compliance with
12  * the License.  You may obtain a copy of the License at
13  *
14  *     http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  */
22
23 /**
24  * {@link CharacterUtils} provides a unified interface to Character-related
25  * operations to implement backwards compatible character operations based on a
26  * {@link Version} instance.
27  * 
28  * @lucene.internal
29  */
30 public abstract class CharacterUtils {
31   private static final Java4CharacterUtils JAVA_4 = new Java4CharacterUtils();
32   private static final Java5CharacterUtils JAVA_5 = new Java5CharacterUtils();
33
34   /**
35    * Returns a {@link CharacterUtils} implementation according to the given
36    * {@link Version} instance.
37    * 
38    * @param matchVersion
39    *          a version instance
40    * @return a {@link CharacterUtils} implementation according to the given
41    *         {@link Version} instance.
42    */
43   public static CharacterUtils getInstance(final Version matchVersion) {
44     return matchVersion.onOrAfter(Version.LUCENE_31) ? JAVA_5 : JAVA_4;
45   }
46
47   /**
48    * Returns the code point at the given index of the char array.
49    * Depending on the {@link Version} passed to
50    * {@link CharacterUtils#getInstance(Version)} this method mimics the behavior
51    * of {@link Character#codePointAt(char[], int)} as it would have been
52    * available on a Java 1.4 JVM or on a later virtual machine version.
53    * 
54    * @param chars
55    *          a character array
56    * @param offset
57    *          the offset to the char values in the chars array to be converted
58    * 
59    * @return the Unicode code point at the given index
60    * @throws NullPointerException
61    *           - if the array is null.
62    * @throws IndexOutOfBoundsException
63    *           - if the value offset is negative or not less than the length of
64    *           the char array.
65    */
66   public abstract int codePointAt(final char[] chars, final int offset);
67
68   /**
69    * Returns the code point at the given index of the {@link CharSequence}.
70    * Depending on the {@link Version} passed to
71    * {@link CharacterUtils#getInstance(Version)} this method mimics the behavior
72    * of {@link Character#codePointAt(char[], int)} as it would have been
73    * available on a Java 1.4 JVM or on a later virtual machine version.
74    * 
75    * @param seq
76    *          a character sequence
77    * @param offset
78    *          the offset to the char values in the chars array to be converted
79    * 
80    * @return the Unicode code point at the given index
81    * @throws NullPointerException
82    *           - if the sequence is null.
83    * @throws IndexOutOfBoundsException
84    *           - if the value offset is negative or not less than the length of
85    *           the character sequence.
86    */
87   public abstract int codePointAt(final CharSequence seq, final int offset);
88   
89   /**
90    * Returns the code point at the given index of the char array where only elements
91    * with index less than the limit are used.
92    * Depending on the {@link Version} passed to
93    * {@link CharacterUtils#getInstance(Version)} this method mimics the behavior
94    * of {@link Character#codePointAt(char[], int)} as it would have been
95    * available on a Java 1.4 JVM or on a later virtual machine version.
96    * 
97    * @param chars
98    *          a character array
99    * @param offset
100    *          the offset to the char values in the chars array to be converted
101    * @param limit the index afer the last element that should be used to calculate
102    *        codepoint.  
103    * 
104    * @return the Unicode code point at the given index
105    * @throws NullPointerException
106    *           - if the array is null.
107    * @throws IndexOutOfBoundsException
108    *           - if the value offset is negative or not less than the length of
109    *           the char array.
110    */
111   public abstract int codePointAt(final char[] chars, final int offset, final int limit);
112   
113   /**
114    * Creates a new {@link CharacterBuffer} and allocates a <code>char[]</code>
115    * of the given bufferSize.
116    * 
117    * @param bufferSize
118    *          the internal char buffer size, must be <code>&gt;= 2</code>
119    * @return a new {@link CharacterBuffer} instance.
120    */
121   public static CharacterBuffer newCharacterBuffer(final int bufferSize) {
122     if(bufferSize < 2)
123       throw new IllegalArgumentException("buffersize must be >= 2");
124     return new CharacterBuffer(new char[bufferSize], 0, 0);
125   }
126
127   /**
128    * Fills the {@link CharacterBuffer} with characters read from the given
129    * reader {@link Reader}. This method tries to read as many characters into
130    * the {@link CharacterBuffer} as possible, each call to fill will start
131    * filling the buffer from offset <code>0</code> up to the length of the size
132    * of the internal character array.
133    * <p>
134    * Depending on the {@link Version} passed to
135    * {@link CharacterUtils#getInstance(Version)} this method implements
136    * supplementary character awareness when filling the given buffer. For all
137    * {@link Version} &gt; 3.0 {@link #fill(CharacterBuffer, Reader)} guarantees
138    * that the given {@link CharacterBuffer} will never contain a high surrogate
139    * character as the last element in the buffer unless it is the last available
140    * character in the reader. In other words, high and low surrogate pairs will
141    * always be preserved across buffer boarders.
142    * </p>
143    * 
144    * @param buffer
145    *          the buffer to fill.
146    * @param reader
147    *          the reader to read characters from.
148    * @return <code>true</code> if and only if no more characters are available
149    *         in the reader, otherwise <code>false</code>.
150    * @throws IOException
151    *           if the reader throws an {@link IOException}.
152    */
153   public abstract boolean fill(CharacterBuffer buffer, Reader reader) throws IOException;
154
155   private static final class Java5CharacterUtils extends CharacterUtils {
156     Java5CharacterUtils() {
157     }
158
159     @Override
160     public final int codePointAt(final char[] chars, final int offset) {
161       return Character.codePointAt(chars, offset);
162     }
163
164     @Override
165     public int codePointAt(final CharSequence seq, final int offset) {
166       return Character.codePointAt(seq, offset);
167     }
168
169     @Override
170     public int codePointAt(final char[] chars, final int offset, final int limit) {
171      return Character.codePointAt(chars, offset, limit);
172     }
173
174     @Override
175     public boolean fill(final CharacterBuffer buffer, final Reader reader) throws IOException {
176       final char[] charBuffer = buffer.buffer;
177       buffer.offset = 0;
178       charBuffer[0] = buffer.lastTrailingHighSurrogate;
179       final int offset = buffer.lastTrailingHighSurrogate == 0 ? 0 : 1;
180       buffer.lastTrailingHighSurrogate = 0;
181       final int read = reader.read(charBuffer, offset, charBuffer.length
182           - offset);
183       if (read == -1) {
184         buffer.length = offset;
185         return offset != 0;
186       }
187       buffer.length = read + offset;
188       // special case if the read returns 0 and the lastTrailingHighSurrogate was set
189       if (buffer.length > 1
190           && Character.isHighSurrogate(charBuffer[buffer.length - 1])) {
191         buffer.lastTrailingHighSurrogate = charBuffer[--buffer.length];
192       }
193       return true;
194     }
195   }
196
197   private static final class Java4CharacterUtils extends CharacterUtils {
198     Java4CharacterUtils() {
199     }
200
201     @Override
202     public final int codePointAt(final char[] chars, final int offset) {
203       return chars[offset];
204     }
205
206     @Override
207     public int codePointAt(final CharSequence seq, final int offset) {
208       return seq.charAt(offset);
209     }
210
211     @Override
212     public int codePointAt(final char[] chars, final int offset, final int limit) {
213       if(offset >= limit)
214         throw new IndexOutOfBoundsException("offset must be less than limit");
215       return chars[offset];
216     }
217
218     @Override
219     public boolean fill(final CharacterBuffer buffer, final Reader reader) throws IOException {
220       buffer.offset = 0;
221       final int read = reader.read(buffer.buffer);
222       if(read == -1)
223         return false;
224       buffer.length = read;
225       return true;
226     }
227
228   }
229   
230   /**
231    * A simple IO buffer to use with
232    * {@link CharacterUtils#fill(CharacterBuffer, Reader)}.
233    */
234   public static final class CharacterBuffer {
235     
236     private final char[] buffer;
237     private int offset;
238     private int length;
239     private char lastTrailingHighSurrogate = 0;
240     
241     CharacterBuffer(char[] buffer, int offset, int length) {
242       this.buffer = buffer;
243       this.offset = offset;
244       this.length = length;
245     }
246     
247     /**
248      * Returns the internal buffer
249      * 
250      * @return the buffer
251      */
252     public char[] getBuffer() {
253       return buffer;
254     }
255     
256     /**
257      * Returns the data offset in the internal buffer.
258      * 
259      * @return the offset
260      */
261     public int getOffset() {
262       return offset;
263     }
264     
265     /**
266      * Return the length of the data in the internal buffer starting at
267      * {@link #getOffset()}
268      * 
269      * @return the length
270      */
271     public int getLength() {
272       return length;
273     }
274     
275     /**
276      * Resets the CharacterBuffer. All internals are reset to its default
277      * values.
278      */
279     public void reset() {
280       offset = 0;
281       length = 0;
282       lastTrailingHighSurrogate = 0;
283     }
284   }
285
286 }