History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/text/normalizer/TrieIterator.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/text/normalizer/TrieIterator.java+548−0
@@ -0,0 +1,548 @@
1/*
2 * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25/*
26 *******************************************************************************
27 * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved *
28 * *
29 * The original version of this source code and documentation is copyrighted *
30 * and owned by IBM, These materials are provided under terms of a License *
31 * Agreement between IBM and Sun. This technology is protected by multiple *
32 * US and International patents. This notice and attribution to IBM may not *
33 * to removed. *
34 *******************************************************************************
35 */
36
37package sun.text.normalizer;
38
39/**
40 * <p>Class enabling iteration of the values in a Trie.</p>
41 * <p>Result of each iteration contains the interval of codepoints that have
42 * the same value type and the value type itself.</p>
43 * <p>The comparison of each codepoint value is done via extract(), which the
44 * default implementation is to return the value as it is.</p>
45 * <p>Method extract() can be overwritten to perform manipulations on
46 * codepoint values in order to perform specialized comparison.</p>
47 * <p>TrieIterator is designed to be a generic iterator for the CharTrie
48 * and the IntTrie, hence to accommodate both types of data, the return
49 * result will be in terms of int (32 bit) values.</p>
50 * <p>See com.ibm.icu.text.UCharacterTypeIterator for examples of use.</p>
51 * <p>Notes for porting utrie_enum from icu4c to icu4j:<br>
52 * Internally, icu4c's utrie_enum performs all iterations in its body. In Java
53 * sense, the caller will have to pass a object with a callback function
54 * UTrieEnumRange(const void *context, UChar32 start, UChar32 limit,
55 * uint32_t value) into utrie_enum. utrie_enum will then find ranges of
56 * codepoints with the same value as determined by
57 * UTrieEnumValue(const void *context, uint32_t value). for each range,
58 * utrie_enum calls the callback function to perform a task. In this way,
59 * icu4c performs the iteration within utrie_enum.
60 * To follow the JDK model, icu4j is slightly different from icu4c.
61 * Instead of requesting the caller to implement an object for a callback.
62 * The caller will have to implement a subclass of TrieIterator, fleshing out
63 * the method extract(int) (equivalent to UTrieEnumValue). Independent of icu4j,
64 * the caller will have to code his own iteration and flesh out the task
65 * (equivalent to UTrieEnumRange) to be performed in the iteration loop.
66 * </p>
67 * <p>There are basically 3 usage scenarios for porting:</p>
68 * <p>1) UTrieEnumValue is the only implemented callback then just implement a
69 * subclass of TrieIterator and override the extract(int) method. The
70 * extract(int) method is analogus to UTrieEnumValue callback.
71 * </p>
72 * <p>2) UTrieEnumValue and UTrieEnumRange both are implemented then implement
73 * a subclass of TrieIterator, override the extract method and iterate, e.g
74 * </p>
75 * <p>utrie_enum(&normTrie, _enumPropertyStartsValue, _enumPropertyStartsRange,
76 * set);<br>
77 * In Java :<br>
78 * <pre>
79 * class TrieIteratorImpl extends TrieIterator{
80 * public TrieIteratorImpl(Trie data){
81 * super(data);
82 * }
83 * public int extract(int value){
84 * // port the implementation of _enumPropertyStartsValue here
85 * }
86 * }
87 * ....
88 * TrieIterator fcdIter = new TrieIteratorImpl(fcdTrieImpl.fcdTrie);
89 * while(fcdIter.next(result)) {
90 * // port the implementation of _enumPropertyStartsRange
91 * }
92 * </pre>
93 * </p>
94 * <p>3) UTrieEnumRange is the only implemented callback then just implement
95 * the while loop, when utrie_enum is called
96 * <pre>
97 * // utrie_enum(&fcdTrie, NULL, _enumPropertyStartsRange, set);
98 * TrieIterator fcdIter = new TrieIterator(fcdTrieImpl.fcdTrie);
99 * while(fcdIter.next(result)){
100 * set.add(result.start);
101 * }
102 * </pre>
103 * </p>
104 * @author synwee
105 * @see com.ibm.icu.impl.Trie
106 * @see com.ibm.icu.lang.UCharacterTypeIterator
107 * @since release 2.1, Jan 17 2002
108 */
109public class TrieIterator implements RangeValueIterator
110{
111
112 // public constructor ---------------------------------------------
113
114 /**
115 * TrieEnumeration constructor
116 * @param trie to be used
117 * @exception IllegalArgumentException throw when argument is null.
118 */
119 public TrieIterator(Trie trie)
120 {
121 if (trie == null) {
122 throw new IllegalArgumentException(
123 "Argument trie cannot be null");
124 }
125 m_trie_ = trie;
126 // synwee: check that extract belongs to the child class
127 m_initialValue_ = extract(m_trie_.getInitialValue());
128 reset();
129 }
130
131 // public methods -------------------------------------------------
132
133 /**
134 * <p>Returns true if we are not at the end of the iteration, false
135 * otherwise.</p>
136 * <p>The next set of codepoints with the same value type will be
137 * calculated during this call and returned in the arguement element.</p>
138 * @param element return result
139 * @return true if we are not at the end of the iteration, false otherwise.
140 * @exception NoSuchElementException - if no more elements exist.
141 * @see com.ibm.icu.util.RangeValueIterator.Element
142 */
143 public final boolean next(Element element)
144 {
145 if (m_nextCodepoint_ > UCharacter.MAX_VALUE) {
146 return false;
147 }
148 if (m_nextCodepoint_ < UCharacter.SUPPLEMENTARY_MIN_VALUE &&
149 calculateNextBMPElement(element)) {
150 return true;
151 }
152 calculateNextSupplementaryElement(element);
153 return true;
154 }
155
156 /**
157 * Resets the iterator to the beginning of the iteration
158 */
159 public final void reset()
160 {
161 m_currentCodepoint_ = 0;
162 m_nextCodepoint_ = 0;
163 m_nextIndex_ = 0;
164 m_nextBlock_ = m_trie_.m_index_[0] << Trie.INDEX_STAGE_2_SHIFT_;
165 if (m_nextBlock_ == 0) {
166 m_nextValue_ = m_initialValue_;
167 }
168 else {
169 m_nextValue_ = extract(m_trie_.getValue(m_nextBlock_));
170 }
171 m_nextBlockIndex_ = 0;
172 m_nextTrailIndexOffset_ = TRAIL_SURROGATE_INDEX_BLOCK_LENGTH_;
173 }
174
175 // protected methods ----------------------------------------------
176
177 /**
178 * Called by next() to extracts a 32 bit value from a trie value
179 * used for comparison.
180 * This method is to be overwritten if special manipulation is to be done
181 * to retrieve a relevant comparison.
182 * The default function is to return the value as it is.
183 * @param value a value from the trie
184 * @return extracted value
185 */
186 protected int extract(int value)
187 {
188 return value;
189 }
190
191 // private methods ------------------------------------------------
192
193 /**
194 * Set the result values
195 * @param element return result object
196 * @param start codepoint of range
197 * @param limit (end + 1) codepoint of range
198 * @param value common value of range
199 */
200 private final void setResult(Element element, int start, int limit,
201 int value)
202 {
203 element.start = start;
204 element.limit = limit;
205 element.value = value;
206 }
207
208 /**
209 * Finding the next element.
210 * This method is called just before returning the result of
211 * next().
212 * We always store the next element before it is requested.
213 * In the case that we have to continue calculations into the
214 * supplementary planes, a false will be returned.
215 * @param element return result object
216 * @return true if the next range is found, false if we have to proceed to
217 * the supplementary range.
218 */
219 private final boolean calculateNextBMPElement(Element element)
220 {
221 int currentBlock = m_nextBlock_;
222 int currentValue = m_nextValue_;
223 m_currentCodepoint_ = m_nextCodepoint_;
224 m_nextCodepoint_ ++;
225 m_nextBlockIndex_ ++;
226 if (!checkBlockDetail(currentValue)) {
227 setResult(element, m_currentCodepoint_, m_nextCodepoint_,
228 currentValue);
229 return true;
230 }
231 // synwee check that next block index == 0 here
232 // enumerate BMP - the main loop enumerates data blocks
233 while (m_nextCodepoint_ < UCharacter.SUPPLEMENTARY_MIN_VALUE) {
234 m_nextIndex_ ++;
235 // because of the way the character is split to form the index
236 // the lead surrogate and trail surrogate can not be in the
237 // mid of a block
238 if (m_nextCodepoint_ == LEAD_SURROGATE_MIN_VALUE_) {
239 // skip lead surrogate code units,
240 // go to lead surrogate codepoints
241 m_nextIndex_ = BMP_INDEX_LENGTH_;
242 }
243 else if (m_nextCodepoint_ == TRAIL_SURROGATE_MIN_VALUE_) {
244 // go back to regular BMP code points
245 m_nextIndex_ = m_nextCodepoint_ >> Trie.INDEX_STAGE_1_SHIFT_;
246 }
247
248 m_nextBlockIndex_ = 0;
249 if (!checkBlock(currentBlock, currentValue)) {
250 setResult(element, m_currentCodepoint_, m_nextCodepoint_,
251 currentValue);
252 return true;
253 }
254 }
255 m_nextCodepoint_ --; // step one back since this value has not been
256 m_nextBlockIndex_ --; // retrieved yet.
257 return false;
258 }
259
260 /**
261 * Finds the next supplementary element.
262 * For each entry in the trie, the value to be delivered is passed through
263 * extract().
264 * We always store the next element before it is requested.
265 * Called after calculateNextBMP() completes its round of BMP characters.
266 * There is a slight difference in the usage of m_currentCodepoint_
267 * here as compared to calculateNextBMP(). Though both represents the
268 * lower bound of the next element, in calculateNextBMP() it gets set
269 * at the start of any loop, where-else, in calculateNextSupplementary()
270 * since m_currentCodepoint_ already contains the lower bound of the
271 * next element (passed down from calculateNextBMP()), we keep it till
272 * the end before resetting it to the new value.
273 * Note, if there are no more iterations, it will never get to here.
274 * Blocked out by next().
275 * @param element return result object
276 */
277 private final void calculateNextSupplementaryElement(Element element)
278 {
279 int currentValue = m_nextValue_;
280 int currentBlock = m_nextBlock_;
281 m_nextCodepoint_ ++;
282 m_nextBlockIndex_ ++;
283
284 if (UTF16.getTrailSurrogate(m_nextCodepoint_)
285 != UTF16.TRAIL_SURROGATE_MIN_VALUE) {
286 // this piece is only called when we are in the middle of a lead
287 // surrogate block
288 if (!checkNullNextTrailIndex() && !checkBlockDetail(currentValue)) {
289 setResult(element, m_currentCodepoint_, m_nextCodepoint_,
290 currentValue);
291 m_currentCodepoint_ = m_nextCodepoint_;
292 return;
293 }
294 // we have cleared one block
295 m_nextIndex_ ++;
296 m_nextTrailIndexOffset_ ++;
297 if (!checkTrailBlock(currentBlock, currentValue)) {
298 setResult(element, m_currentCodepoint_, m_nextCodepoint_,
299 currentValue);
300 m_currentCodepoint_ = m_nextCodepoint_;
301 return;
302 }
303 }
304 int nextLead = UTF16.getLeadSurrogate(m_nextCodepoint_);
305 // enumerate supplementary code points
306 while (nextLead < TRAIL_SURROGATE_MIN_VALUE_) {
307 // lead surrogate access
308 int leadBlock =
309 m_trie_.m_index_[nextLead >> Trie.INDEX_STAGE_1_SHIFT_] <<
310 Trie.INDEX_STAGE_2_SHIFT_;
311 if (leadBlock == m_trie_.m_dataOffset_) {
312 // no entries for a whole block of lead surrogates
313 if (currentValue != m_initialValue_) {
314 m_nextValue_ = m_initialValue_;
315 m_nextBlock_ = 0;
316 m_nextBlockIndex_ = 0;
317 setResult(element, m_currentCodepoint_, m_nextCodepoint_,
318 currentValue);
319 m_currentCodepoint_ = m_nextCodepoint_;
320 return;
321 }
322
323 nextLead += DATA_BLOCK_LENGTH_;
324 // number of total affected supplementary codepoints in one
325 // block
326 // this is not a simple addition of
327 // DATA_BLOCK_SUPPLEMENTARY_LENGTH since we need to consider
328 // that we might have moved some of the codepoints
329 m_nextCodepoint_ = UCharacterProperty.getRawSupplementary(
330 (char)nextLead,
331 (char)UTF16.TRAIL_SURROGATE_MIN_VALUE);
332 continue;
333 }
334 if (m_trie_.m_dataManipulate_ == null) {
335 throw new NullPointerException(
336 "The field DataManipulate in this Trie is null");
337 }
338 // enumerate trail surrogates for this lead surrogate
339 m_nextIndex_ = m_trie_.m_dataManipulate_.getFoldingOffset(
340 m_trie_.getValue(leadBlock +
341 (nextLead & Trie.INDEX_STAGE_3_MASK_)));
342 if (m_nextIndex_ <= 0) {
343 // no data for this lead surrogate
344 if (currentValue != m_initialValue_) {
345 m_nextValue_ = m_initialValue_;
346 m_nextBlock_ = 0;
347 m_nextBlockIndex_ = 0;
348 setResult(element, m_currentCodepoint_, m_nextCodepoint_,
349 currentValue);
350 m_currentCodepoint_ = m_nextCodepoint_;
351 return;
352 }
353 m_nextCodepoint_ += TRAIL_SURROGATE_COUNT_;
354 } else {
355 m_nextTrailIndexOffset_ = 0;
356 if (!checkTrailBlock(currentBlock, currentValue)) {
357 setResult(element, m_currentCodepoint_, m_nextCodepoint_,
358 currentValue);
359 m_currentCodepoint_ = m_nextCodepoint_;
360 return;
361 }
362 }
363 nextLead ++;
364 }
365
366 // deliver last range
367 setResult(element, m_currentCodepoint_, UCharacter.MAX_VALUE + 1,
368 currentValue);
369 }
370
371 /**
372 * Internal block value calculations
373 * Performs calculations on a data block to find codepoints in m_nextBlock_
374 * after the index m_nextBlockIndex_ that has the same value.
375 * Note m_*_ variables at this point is the next codepoint whose value
376 * has not been calculated.
377 * But when returned with false, it will be the last codepoint whose
378 * value has been calculated.
379 * @param currentValue the value which other codepoints are tested against
380 * @return true if the whole block has the same value as currentValue or if
381 * the whole block has been calculated, false otherwise.
382 */
383 private final boolean checkBlockDetail(int currentValue)
384 {
385 while (m_nextBlockIndex_ < DATA_BLOCK_LENGTH_) {
386 m_nextValue_ = extract(m_trie_.getValue(m_nextBlock_ +
387 m_nextBlockIndex_));
388 if (m_nextValue_ != currentValue) {
389 return false;
390 }
391 ++ m_nextBlockIndex_;
392 ++ m_nextCodepoint_;
393 }
394 return true;
395 }
396
397 /**
398 * Internal block value calculations
399 * Performs calculations on a data block to find codepoints in m_nextBlock_
400 * that has the same value.
401 * Will call checkBlockDetail() if highlevel check fails.
402 * Note m_*_ variables at this point is the next codepoint whose value
403 * has not been calculated.
404 * @param currentBlock the initial block containing all currentValue
405 * @param currentValue the value which other codepoints are tested against
406 * @return true if the whole block has the same value as currentValue or if
407 * the whole block has been calculated, false otherwise.
408 */
409 private final boolean checkBlock(int currentBlock, int currentValue)
410 {
411 m_nextBlock_ = m_trie_.m_index_[m_nextIndex_] <<
412 Trie.INDEX_STAGE_2_SHIFT_;
413 if (m_nextBlock_ == currentBlock &&
414 (m_nextCodepoint_ - m_currentCodepoint_) >= DATA_BLOCK_LENGTH_) {
415 // the block is the same as the previous one, filled with
416 // currentValue
417 m_nextCodepoint_ += DATA_BLOCK_LENGTH_;
418 }
419 else if (m_nextBlock_ == 0) {
420 // this is the all-initial-value block
421 if (currentValue != m_initialValue_) {
422 m_nextValue_ = m_initialValue_;
423 m_nextBlockIndex_ = 0;
424 return false;
425 }
426 m_nextCodepoint_ += DATA_BLOCK_LENGTH_;
427 }
428 else {
429 if (!checkBlockDetail(currentValue)) {
430 return false;
431 }
432 }
433 return true;
434 }
435
436 /**
437 * Internal block value calculations
438 * Performs calculations on multiple data blocks for a set of trail
439 * surrogates to find codepoints in m_nextBlock_ that has the same value.
440 * Will call checkBlock() for internal block checks.
441 * Note m_*_ variables at this point is the next codepoint whose value
442 * has not been calculated.
443 * @param currentBlock the initial block containing all currentValue
444 * @param currentValue the value which other codepoints are tested against
445 * @return true if the whole block has the same value as currentValue or if
446 * the whole block has been calculated, false otherwise.
447 */
448 private final boolean checkTrailBlock(int currentBlock,
449 int currentValue)
450 {
451 // enumerate code points for this lead surrogate
452 while (m_nextTrailIndexOffset_ < TRAIL_SURROGATE_INDEX_BLOCK_LENGTH_)
453 {
454 // if we ever reach here, we are at the start of a new block
455 m_nextBlockIndex_ = 0;
456 // copy of most of the body of the BMP loop
457 if (!checkBlock(currentBlock, currentValue)) {
458 return false;
459 }
460 m_nextTrailIndexOffset_ ++;
461 m_nextIndex_ ++;
462 }
463 return true;
464 }
465
466 /**
467 * Checks if we are beginning at the start of a initial block.
468 * If we are then the rest of the codepoints in this initial block
469 * has the same values.
470 * We increment m_nextCodepoint_ and relevant data members if so.
471 * This is used only in for the supplementary codepoints because
472 * the offset to the trail indexes could be 0.
473 * @return true if we are at the start of a initial block.
474 */
475 private final boolean checkNullNextTrailIndex()
476 {
477 if (m_nextIndex_ <= 0) {
478 m_nextCodepoint_ += TRAIL_SURROGATE_COUNT_ - 1;
479 int nextLead = UTF16.getLeadSurrogate(m_nextCodepoint_);
480 int leadBlock =
481 m_trie_.m_index_[nextLead >> Trie.INDEX_STAGE_1_SHIFT_] <<
482 Trie.INDEX_STAGE_2_SHIFT_;
483 if (m_trie_.m_dataManipulate_ == null) {
484 throw new NullPointerException(
485 "The field DataManipulate in this Trie is null");
486 }
487 m_nextIndex_ = m_trie_.m_dataManipulate_.getFoldingOffset(
488 m_trie_.getValue(leadBlock +
489 (nextLead & Trie.INDEX_STAGE_3_MASK_)));
490 m_nextIndex_ --;
491 m_nextBlockIndex_ = DATA_BLOCK_LENGTH_;
492 return true;
493 }
494 return false;
495 }
496
497 // private data members --------------------------------------------
498
499 /**
500 * Size of the stage 1 BMP indexes
501 */
502 private static final int BMP_INDEX_LENGTH_ =
503 0x10000 >> Trie.INDEX_STAGE_1_SHIFT_;
504 /**
505 * Lead surrogate minimum value
506 */
507 private static final int LEAD_SURROGATE_MIN_VALUE_ = 0xD800;
508 /**
509 * Trail surrogate minimum value
510 */
511 private static final int TRAIL_SURROGATE_MIN_VALUE_ = 0xDC00;
512 /**
513 * Number of trail surrogate
514 */
515 private static final int TRAIL_SURROGATE_COUNT_ = 0x400;
516 /**
517 * Number of stage 1 indexes for supplementary calculations that maps to
518 * each lead surrogate character.
519 * See second pass into getRawOffset for the trail surrogate character.
520 * 10 for significant number of bits for trail surrogates, 5 for what we
521 * discard during shifting.
522 */
523 private static final int TRAIL_SURROGATE_INDEX_BLOCK_LENGTH_ =
524 1 << (10 - Trie.INDEX_STAGE_1_SHIFT_);
525 /**
526 * Number of data values in a stage 2 (data array) block.
527 */
528 private static final int DATA_BLOCK_LENGTH_ =
529 1 << Trie.INDEX_STAGE_1_SHIFT_;
530 /**
531 * Trie instance
532 */
533 private Trie m_trie_;
534 /**
535 * Initial value for trie values
536 */
537 private int m_initialValue_;
538 /**
539 * Next element results and data.
540 */
541 private int m_currentCodepoint_;
542 private int m_nextCodepoint_;
543 private int m_nextValue_;
544 private int m_nextIndex_;
545 private int m_nextBlock_;
546 private int m_nextBlockIndex_;
547 private int m_nextTrailIndexOffset_;
548}