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+
37+package 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+ */
109+public 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+}